addnews 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. #!/bin/bash
  2. #
  3. # addnews
  4. #
  5. # News addition helper for the Dragora GNU/Linux-Libre website
  6. # (https://www.dragora.org)
  7. #
  8. #
  9. # Copyright (C) 2021 Michael Siegel
  10. #
  11. # Licensed under the Apache License, Version 2.0 (the "License");
  12. # you may not use this file except in compliance with the License.
  13. # You may obtain a copy of the License at
  14. #
  15. # http://www.apache.org/licenses/LICENSE-2.0
  16. #
  17. # Unless required by applicable law or agreed to in writing, software
  18. # distributed under the License is distributed on an "AS IS" BASIS,
  19. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  20. # See the License for the specific language governing permissions and
  21. # limitations under the License.
  22. #### INCLUDES ####
  23. . include/constants || exit 1
  24. . include/subroutines || exit 1
  25. #### CONSTANTS ####
  26. #### GLOBAL PARAMETERS ####
  27. action=add
  28. date=
  29. title=
  30. url=
  31. #### FUNCTIONS ####
  32. _days_in_month() {
  33. local month="$1"
  34. local year="$2" # Needs to be YYYY.
  35. local days_in_month=(31 28 31 30 31 30 31 31 30 31 30 31)
  36. month="${month#0}" # Strip leading zeroes for use in arithmetic expansion
  37. if [[ "$month" -eq 2 ]]
  38. then
  39. # Give February 29 days if $year is a leap year:
  40. [[ ("$((year % 4))" -eq 0 && "$((year % 100))" -ne 0) || \
  41. "$((year % 400))" -eq 0 ]] && days_in_month[1]=29
  42. fi
  43. printf '%s' "${days_in_month["$((month - 1))"]}"
  44. }
  45. _date_valid () {
  46. local input="$1"
  47. local day=
  48. local month=
  49. local year=
  50. local days_max=
  51. local valid=1
  52. if [[ ! "$input" =~ [0-9]{4}-[0-9]{2}-[0-9]{2} ]]
  53. then
  54. valid=0
  55. else
  56. year="${input:0:4}"
  57. month="${input:5:2}"
  58. day="${input:8:2}"
  59. if (( 10#"$month" < 1 || 10#"$month" > 12 ))
  60. then
  61. _perr "invalid month -- '$month'"
  62. valid=0
  63. else
  64. days_max="$(_days_in_month "$month" "$year")"
  65. if (( 10#"$day" < 1 || 10#"$day" > 10#"$days_max" ))
  66. then
  67. _perr "invalid day of month -- '$day'"
  68. valid=0
  69. else
  70. date_unix_time="$(TZ="$TIMEZONE" \
  71. date -d "${year#0}-${month#0}-${day#0}" '+%s')"
  72. if (( 10#"$date_unix_time" < 0 ))
  73. then
  74. _perr "date out of range (negative Unix time) -- '$input'"
  75. valid=0
  76. fi
  77. fi
  78. fi
  79. fi
  80. [[ "$valid" -eq 0 ]] && return 1
  81. return 0
  82. }
  83. _prompt_date() {
  84. local input=
  85. local date_default; date_default="$(date +%Y-%m-%d)"
  86. while true
  87. do
  88. if [[ -z "$input" ]]
  89. then
  90. printf '%s\n' "Please enter the publishing date [$date_default]:"
  91. printf '%s\n' "$HELP_TIP_INTERACTIVE"
  92. fi
  93. read -rp "$PROMPT" input
  94. if [[ -z "$input" ]]
  95. then
  96. date="$date_default"
  97. break
  98. elif [[ "$input" = "$HELP_COMMAND" ]]
  99. then
  100. _show_help "$FUNCNAME"
  101. elif ! _date_valid "$input" # _date_valid prints error messages.
  102. then
  103. printf '%s\n' "$HELP_TIP_INTERACTIVE"
  104. else
  105. date="$input"
  106. break
  107. fi
  108. done
  109. }
  110. _prompt_title() {
  111. local input=
  112. while true
  113. do
  114. if [[ -z "$input" ]]
  115. then
  116. printf '%s\n' 'Please enter a title:'
  117. printf '%s\n' "$HELP_TIP_INTERACTIVE"
  118. fi
  119. read -rp "$PROMPT" input
  120. if [[ -z "$input" ]]
  121. then
  122. continue
  123. elif [[ "$input" = "$HELP_COMMAND" ]]
  124. then
  125. _show_help "$FUNCNAME"
  126. else
  127. break
  128. fi
  129. done
  130. title="$input"
  131. }
  132. _prompt_url() {
  133. local input=
  134. local url_pattern='^https://lists\.nongnu\.org/archive/html/dragora-users/[0-9]{4}-[0-9]{2}/msg[0-9]+\.html$'
  135. # Hard-coded 'https' because plain HTTP access not available.
  136. # Kept number of digits before '.html' flexible because not sure if it's
  137. # constant.
  138. while true
  139. do
  140. if [[ -z "$input" ]]
  141. then
  142. printf '%s\n' 'Please enter a URL:'
  143. printf '%s\n' "$HELP_TIP_INTERACTIVE"
  144. fi
  145. read -rp "$PROMPT" input
  146. if [[ -z "$input" ]]
  147. then
  148. continue
  149. elif [[ "$input" = "$HELP_COMMAND" ]]
  150. then
  151. _show_help "$FUNCNAME"
  152. elif [[ ! ("$input" =~ $url_pattern) ]]
  153. then
  154. _perr "invalid URL -- '$input'"
  155. else
  156. break
  157. fi
  158. done
  159. url="$input"
  160. }
  161. _mk_news_item() {
  162. printf ' <li>%s\\n <a href="%s">%s</a>\\n </li>' "$date" "$url" "$title"
  163. # Escaping `\n` so the result can be used in sed.
  164. }
  165. _add_news() {
  166. local news_pg=
  167. local lang=
  168. for lang in $(_get_lang_dirs)
  169. do
  170. news_pg="${PAGES_DIR}/${lang}/$NEWS_PAGE"
  171. cp -a -- "$news_pg" "$news_pg".old
  172. sed -i -- "s|<ul>|<ul>\n$(_mk_news_item)|" "$news_pg"
  173. done
  174. unset lang
  175. }
  176. _revert() {
  177. local news_pg=
  178. local lang=
  179. for lang in $(_get_lang_dirs)
  180. do
  181. news_pg="${PAGES_DIR}/${lang}/$NEWS_PAGE"
  182. if [[ -e "$news_pg".old ]]
  183. then
  184. mv -- "$news_pg".old "$news_pg" || return 1
  185. else
  186. _perr "cannot find backup file -- ${news_pg}.old"
  187. fi
  188. done
  189. unset lang
  190. }
  191. _show_help() {
  192. case "$1" in
  193. global)
  194. cat <<'EOF'
  195. Add a news item interactively
  196. Usage:
  197. addnews [OPTIONS]
  198. Options:
  199. -r Revert latest news addition
  200. --help
  201. Show this help text and exit
  202. EOF
  203. ;;
  204. *)
  205. printf '%s\n' "Sorry, no help text available."
  206. ;;
  207. esac
  208. }
  209. #### MAIN ####
  210. ## Environment checks
  211. _env_checks || _abort
  212. ## Action
  213. while [[ "$#" -gt 0 ]]
  214. do
  215. case "$1" in
  216. -r)
  217. shift
  218. action=revert
  219. ;;
  220. --help)
  221. _show_help global
  222. exit
  223. ;;
  224. --) # End of options
  225. shift
  226. break
  227. ;;
  228. *)
  229. _perr "invalid argument -- '$1'"
  230. exit 1
  231. ;;
  232. esac
  233. done
  234. if [[ "$action" = revert ]]
  235. then
  236. _revert || _abort
  237. else
  238. _prompt_date || _abort
  239. _prompt_title || _abort
  240. _prompt_url || _abort
  241. _add_news || _abort
  242. fi