views.go 61 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485
  1. // Code generated by go generate; DO NOT EDIT.
  2. package template // import "miniflux.app/template"
  3. var templateViewsMap = map[string]string{
  4. "about": `{{ define "title"}}{{ t "page.about.title" }}{{ end }}
  5. {{ define "content"}}
  6. <section class="page-header">
  7. <h1>{{ t "page.about.title" }}</h1>
  8. <ul>
  9. <li>
  10. <a href="{{ route "settings" }}">{{ t "menu.preferences" }}</a>
  11. </li>
  12. <li>
  13. <a href="{{ route "integrations" }}">{{ t "menu.integrations" }}</a>
  14. </li>
  15. <li>
  16. <a href="{{ route "sessions" }}">{{ t "menu.sessions" }}</a>
  17. </li>
  18. {{ if .user.IsAdmin }}
  19. <li>
  20. <a href="{{ route "users" }}">{{ t "menu.users" }}</a>
  21. </li>
  22. {{ end }}
  23. </ul>
  24. </section>
  25. <div class="panel">
  26. <h3>Miniflux</h3>
  27. <ul>
  28. <li><strong>{{ t "page.about.version" }}</strong> {{ .version }}</li>
  29. <li><strong>{{ t "page.about.build_date" }}</strong> {{ .build_date }}</li>
  30. </ul>
  31. </div>
  32. <div class="panel">
  33. <h3>{{ t "page.about.credits" }}</h3>
  34. <ul>
  35. <li><strong>{{ t "page.about.author" }}</strong> Frédéric Guillot</li>
  36. <li><strong>{{ t "page.about.license" }}</strong> Apache 2.0</li>
  37. </ul>
  38. </div>
  39. {{ end }}
  40. `,
  41. "add_subscription": `{{ define "title"}}{{ t "page.add_feed.title" }}{{ end }}
  42. {{ define "content"}}
  43. <section class="page-header">
  44. <h1>{{ t "page.add_feed.title" }}</h1>
  45. <ul>
  46. <li>
  47. <a href="{{ route "feeds" }}">{{ t "menu.feeds" }}</a>
  48. </li>
  49. <li>
  50. <a href="{{ route "export" }}">{{ t "menu.export" }}</a>
  51. </li>
  52. <li>
  53. <a href="{{ route "import" }}">{{ t "menu.import" }}</a>
  54. </li>
  55. </ul>
  56. </section>
  57. {{ if not .categories }}
  58. <p class="alert alert-error">{{ t "page.add_feed.no_category" }}</p>
  59. {{ else }}
  60. <form action="{{ route "submitSubscription" }}" method="post" autocomplete="off">
  61. <input type="hidden" name="csrf" value="{{ .csrf }}">
  62. {{ if .errorMessage }}
  63. <div class="alert alert-error">{{ t .errorMessage }}</div>
  64. {{ end }}
  65. <label for="form-url">{{ t "page.add_feed.label.url" }}</label>
  66. <input type="url" name="url" id="form-url" placeholder="https://domain.tld/" value="{{ .form.URL }}" required autofocus>
  67. <label for="form-category">{{ t "form.feed.label.category" }}</label>
  68. <select id="form-category" name="category_id">
  69. {{ range .categories }}
  70. <option value="{{ .ID }}" {{ if eq $.form.CategoryID .ID }}selected="selected"{{ end }}>{{ .Title }}</option>
  71. {{ end }}
  72. </select>
  73. <details>
  74. <summary>{{ t "page.add_feed.legend.advanced_options" }}</summary>
  75. <div class="details-content">
  76. <label><input type="checkbox" name="crawler" value="1" {{ if .form.Crawler }}checked{{ end }}> {{ t "form.feed.label.crawler" }}</label>
  77. <label for="form-user-agent">{{ t "form.feed.label.user_agent" }}</label>
  78. <input type="text" name="user_agent" id="form-user-agent" placeholder="{{ .defaultUserAgent }}" value="{{ .form.UserAgent }}" autocomplete="off">
  79. <label for="form-feed-username">{{ t "form.feed.label.feed_username" }}</label>
  80. <input type="text" name="feed_username" id="form-feed-username" value="{{ .form.Username }}">
  81. <label for="form-feed-password">{{ t "form.feed.label.feed_password" }}</label>
  82. <!--
  83. We are using the type "text" otherwise Firefox always autocomplete this password:
  84. - autocomplete="off" or autocomplete="new-password" doesn't change anything
  85. - Changing the input ID doesn't change anything
  86. - Using a different input name doesn't change anything
  87. -->
  88. <input type="text" name="feed_password" id="form-feed-password" value="{{ .form.Password }}">
  89. </div>
  90. </details>
  91. <div class="buttons">
  92. <button type="submit" class="button button-primary" data-label-loading="{{ t "form.submit.loading" }}">{{ t "page.add_feed.submit" }}</button>
  93. </div>
  94. </form>
  95. {{ end }}
  96. {{ end }}
  97. `,
  98. "bookmark_entries": `{{ define "title"}}{{ t "page.starred.title" }} ({{ .total }}){{ end }}
  99. {{ define "content"}}
  100. <section class="page-header">
  101. <h1>{{ t "page.starred.title" }} ({{ .total }})</h1>
  102. </section>
  103. {{ if not .entries }}
  104. <p class="alert alert-info">{{ t "alert.no_bookmark" }}</p>
  105. {{ else }}
  106. <div class="items">
  107. {{ range .entries }}
  108. <article class="item touch-item item-status-{{ .Status }}" data-id="{{ .ID }}">
  109. <div class="item-header">
  110. <span class="item-title">
  111. {{ if ne .Feed.Icon.IconID 0 }}
  112. <img src="{{ route "icon" "iconID" .Feed.Icon.IconID }}" width="16" height="16" alt="{{ .Feed.Title }}">
  113. {{ end }}
  114. <a href="{{ route "starredEntry" "entryID" .ID }}">{{ .Title }}</a>
  115. </span>
  116. <span class="category"><a href="{{ route "categoryEntries" "categoryID" .Feed.Category.ID }}">{{ .Feed.Category.Title }}</a></span>
  117. </div>
  118. {{ template "item_meta" dict "user" $.user "entry" . "hasSaveEntry" $.hasSaveEntry }}
  119. </article>
  120. {{ end }}
  121. </div>
  122. {{ template "pagination" .pagination }}
  123. {{ end }}
  124. {{ end }}
  125. `,
  126. "categories": `{{ define "title"}}{{ t "page.categories.title" }} ({{ .total }}){{ end }}
  127. {{ define "content"}}
  128. <section class="page-header">
  129. <h1>{{ t "page.categories.title" }} ({{ .total }})</h1>
  130. <ul>
  131. <li>
  132. <a href="{{ route "createCategory" }}">{{ t "menu.create_category" }}</a>
  133. </li>
  134. </ul>
  135. </section>
  136. {{ if not .categories }}
  137. <p class="alert alert-error">{{ t "alert.no_category" }}</p>
  138. {{ else }}
  139. <div class="items">
  140. {{ range .categories }}
  141. <article class="item">
  142. <div class="item-header">
  143. <span class="item-title">
  144. <a href="{{ route "categoryEntries" "categoryID" .ID }}">{{ .Title }}</a>
  145. </span>
  146. </div>
  147. <div class="item-meta">
  148. <ul>
  149. <li>
  150. {{ if eq .FeedCount 0 }}
  151. {{ t "page.categories.no_feed" }}
  152. {{ else }}
  153. {{ plural "page.categories.feed_count" .FeedCount .FeedCount }}
  154. {{ end }}
  155. </li>
  156. </ul>
  157. <ul>
  158. <li>
  159. <a href="{{ route "editCategory" "categoryID" .ID }}">{{ t "menu.edit_category" }}</a>
  160. </li>
  161. {{ if eq .FeedCount 0 }}
  162. <li>
  163. <a href="#"
  164. data-confirm="true"
  165. data-label-question="{{ t "confirm.question" }}"
  166. data-label-yes="{{ t "confirm.yes" }}"
  167. data-label-no="{{ t "confirm.no" }}"
  168. data-label-loading="{{ t "confirm.loading" }}"
  169. data-url="{{ route "removeCategory" "categoryID" .ID }}">{{ t "action.remove" }}</a>
  170. </li>
  171. {{ end }}
  172. </ul>
  173. </div>
  174. </article>
  175. {{ end }}
  176. </div>
  177. {{ end }}
  178. {{ end }}
  179. `,
  180. "category_entries": `{{ define "title"}}{{ .category.Title }} ({{ .total }}){{ end }}
  181. {{ define "content"}}
  182. <section class="page-header">
  183. <h1>{{ .category.Title }} ({{ .total }})</h1>
  184. <ul>
  185. {{ if .entries }}
  186. <li>
  187. <a href="#"
  188. data-confirm="true"
  189. data-label-question="{{ t "confirm.question" }}"
  190. data-label-yes="{{ t "confirm.yes" }}"
  191. data-label-no="{{ t "confirm.no" }}"
  192. data-label-loading="{{ t "confirm.loading" }}"
  193. data-show-only-unread="{{ if .showOnlyUnreadEntries }}1{{ end }}"
  194. data-mark-page-as-read="true">
  195. {{ t "menu.mark_page_as_read" }}
  196. </a>
  197. </li>
  198. {{ end }}
  199. {{ if .showOnlyUnreadEntries }}
  200. <li>
  201. <a href="{{ route "categoryEntriesAll" "categoryID" .category.ID }}">{{ t "menu.show_all_entries" }}</a>
  202. </li>
  203. {{ else }}
  204. <li>
  205. <a href="{{ route "categoryEntries" "categoryID" .category.ID }}">{{ t "menu.show_only_unread_entries" }}</a>
  206. </li>
  207. {{ end }}
  208. </ul>
  209. </section>
  210. {{ if not .entries }}
  211. <p class="alert">{{ t "alert.no_category_entry" }}</p>
  212. {{ else }}
  213. <div class="items">
  214. {{ range .entries }}
  215. <article class="item touch-item item-status-{{ .Status }}" data-id="{{ .ID }}">
  216. <div class="item-header">
  217. <span class="item-title">
  218. {{ if ne .Feed.Icon.IconID 0 }}
  219. <img src="{{ route "icon" "iconID" .Feed.Icon.IconID }}" width="16" height="16" alt="{{ .Feed.Title }}">
  220. {{ end }}
  221. <a href="{{ route "categoryEntry" "categoryID" .Feed.Category.ID "entryID" .ID }}">{{ .Title }}</a>
  222. </span>
  223. <span class="category"><a href="{{ route "categoryEntries" "categoryID" .Feed.Category.ID }}">{{ .Feed.Category.Title }}</a></span>
  224. </div>
  225. {{ template "item_meta" dict "user" $.user "entry" . "hasSaveEntry" $.hasSaveEntry }}
  226. </article>
  227. {{ end }}
  228. </div>
  229. <section class="page-footer">
  230. {{ if .entries }}
  231. <ul>
  232. <li>
  233. <a href="#"
  234. data-confirm="true"
  235. data-label-question="{{ t "confirm.question" }}"
  236. data-label-yes="{{ t "confirm.yes" }}"
  237. data-label-no="{{ t "confirm.no" }}"
  238. data-label-loading="{{ t "confirm.loading" }}"
  239. data-show-only-unread="{{ if .showOnlyUnreadEntries }}1{{ end }}"
  240. data-mark-page-as-read="true">
  241. {{ t "menu.mark_page_as_read" }}
  242. </a>
  243. </li>
  244. </ul>
  245. {{ end }}
  246. </section>
  247. {{ template "pagination" .pagination }}
  248. {{ end }}
  249. {{ end }}
  250. `,
  251. "choose_subscription": `{{ define "title"}}{{ t "page.add_feed.title" }}{{ end }}
  252. {{ define "content"}}
  253. <section class="page-header">
  254. <h1>{{ t "page.add_feed.title" }}</h1>
  255. <ul>
  256. <li>
  257. <a href="{{ route "feeds" }}">{{ t "menu.feeds" }}</a>
  258. </li>
  259. <li>
  260. <a href="{{ route "export" }}">{{ t "menu.export" }}</a>
  261. </li>
  262. <li>
  263. <a href="{{ route "import" }}">{{ t "menu.import" }}</a>
  264. </li>
  265. </ul>
  266. </section>
  267. <form action="{{ route "chooseSubscription" }}" method="POST">
  268. <input type="hidden" name="csrf" value="{{ .csrf }}">
  269. <input type="hidden" name="category_id" value="{{ .form.CategoryID }}">
  270. <input type="hidden" name="user_agent" value="{{ .form.UserAgent }}">
  271. <input type="hidden" name="feed_username" value="{{ .form.Username }}">
  272. <input type="hidden" name="feed_password" value="{{ .form.Password }}">
  273. {{ if .form.Crawler }}
  274. <input type="hidden" name="crawler" value="1">
  275. {{ end }}
  276. <h3>{{ t "page.add_feed.choose_feed" }}</h3>
  277. {{ range .subscriptions }}
  278. <div class="radio-group">
  279. <label title="{{ .URL }}"><input type="radio" name="url" value="{{ .URL }}"> {{ .Title }}</label> ({{ .Type }})
  280. <small title="Type = {{ .Type }}"><a href="{{ .URL }}" target="_blank" rel="noopener noreferrer" referrerpolicy="no-referrer">{{ .URL }}</a></small>
  281. </div>
  282. {{ end }}
  283. <div class="buttons">
  284. <button type="submit" class="button button-primary" data-label-loading="{{ t "form.submit.loading" }}">{{ t "action.subscribe" }}</button>
  285. </div>
  286. </form>
  287. {{ end }}
  288. `,
  289. "create_category": `{{ define "title"}}{{ t "page.new_category.title" }}{{ end }}
  290. {{ define "content"}}
  291. <section class="page-header">
  292. <h1>{{ t "page.new_category.title" }}</h1>
  293. <ul>
  294. <li>
  295. <a href="{{ route "categories" }}">{{ t "menu.categories" }}</a>
  296. </li>
  297. </ul>
  298. </section>
  299. <form action="{{ route "saveCategory" }}" method="post" autocomplete="off">
  300. <input type="hidden" name="csrf" value="{{ .csrf }}">
  301. {{ if .errorMessage }}
  302. <div class="alert alert-error">{{ t .errorMessage }}</div>
  303. {{ end }}
  304. <label for="form-title">{{ t "form.category.label.title" }}</label>
  305. <input type="text" name="title" id="form-title" value="{{ .form.Title }}" required autofocus>
  306. <div class="buttons">
  307. <button type="submit" class="button button-primary" data-label-loading="{{ t "form.submit.saving" }}">{{ t "action.save" }}</button> {{ t "action.or" }} <a href="{{ route "categories" }}">{{ t "action.cancel" }}</a>
  308. </div>
  309. </form>
  310. {{ end }}
  311. `,
  312. "create_user": `{{ define "title"}}{{ t "page.new_user.title" }}{{ end }}
  313. {{ define "content"}}
  314. <section class="page-header">
  315. <h1>{{ t "page.new_user.title" }}</h1>
  316. <ul>
  317. <li>
  318. <a href="{{ route "settings" }}">{{ t "menu.settings" }}</a>
  319. </li>
  320. <li>
  321. <a href="{{ route "integrations" }}">{{ t "menu.integrations" }}</a>
  322. </li>
  323. <li>
  324. <a href="{{ route "sessions" }}">{{ t "menu.sessions" }}</a>
  325. </li>
  326. <li>
  327. <a href="{{ route "users" }}">{{ t "menu.users" }}</a>
  328. </li>
  329. <li>
  330. <a href="{{ route "about" }}">{{ t "menu.about" }}</a>
  331. </li>
  332. </ul>
  333. </section>
  334. <form action="{{ route "saveUser" }}" method="post" autocomplete="off">
  335. <input type="hidden" name="csrf" value="{{ .csrf }}">
  336. {{ if .errorMessage }}
  337. <div class="alert alert-error">{{ t .errorMessage }}</div>
  338. {{ end }}
  339. <label for="form-username">{{ t "form.user.label.username" }}</label>
  340. <input type="text" name="username" id="form-username" value="{{ .form.Username }}" autocomplete="new-password" required autofocus>
  341. <label for="form-password">{{ t "form.user.label.password" }}</label>
  342. <input type="password" name="password" id="form-password" value="{{ .form.Password }}" autocomplete="new-password" required>
  343. <label for="form-confirmation">{{ t "form.user.label.confirmation" }}</label>
  344. <input type="password" name="confirmation" id="form-confirmation" value="{{ .form.Confirmation }}" required>
  345. <label><input type="checkbox" name="is_admin" value="1" {{ if .form.IsAdmin }}checked{{ end }}> {{ t "form.user.label.admin" }}</label>
  346. <div class="buttons">
  347. <button type="submit" class="button button-primary" data-label-loading="{{ t "form.submit.saving" }}">{{ t "action.save" }}</button> {{ t "action.or" }} <a href="{{ route "users" }}">{{ t "action.cancel" }}</a>
  348. </div>
  349. </form>
  350. {{ end }}
  351. `,
  352. "edit_category": `{{ define "title"}}{{ t "page.edit_category.title" .category.Title }}{{ end }}
  353. {{ define "content"}}
  354. <section class="page-header">
  355. <h1>{{ t "page.edit_category.title" .category.Title }}</h1>
  356. <ul>
  357. <li>
  358. <a href="{{ route "categories" }}">{{ t "menu.categories" }}</a>
  359. </li>
  360. <li>
  361. <a href="{{ route "createCategory" }}">{{ t "menu.create_category" }}</a>
  362. </li>
  363. </ul>
  364. </section>
  365. <form action="{{ route "updateCategory" "categoryID" .category.ID }}" method="post" autocomplete="off">
  366. <input type="hidden" name="csrf" value="{{ .csrf }}">
  367. {{ if .errorMessage }}
  368. <div class="alert alert-error">{{ t .errorMessage }}</div>
  369. {{ end }}
  370. <label for="form-title">{{ t "form.category.label.title" }}</label>
  371. <input type="text" name="title" id="form-title" value="{{ .form.Title }}" required autofocus>
  372. <div class="buttons">
  373. <button type="submit" class="button button-primary" data-label-loading="{{ t "form.submit.saving" }}">{{ t "action.update" }}</button> {{ t "action.or" }} <a href="{{ route "categories" }}">{{ t "action.cancel" }}</a>
  374. </div>
  375. </form>
  376. {{ end }}
  377. `,
  378. "edit_feed": `{{ define "title"}}{{ t "page.edit_feed.title" .feed.Title }}{{ end }}
  379. {{ define "content"}}
  380. <section class="page-header">
  381. <h1>{{ .feed.Title }}</h1>
  382. <ul>
  383. <li>
  384. <a href="{{ route "feeds" }}">{{ t "menu.feeds" }}</a>
  385. </li>
  386. <li>
  387. <a href="{{ route "addSubscription" }}">{{ t "menu.add_feed" }}</a>
  388. </li>
  389. <li>
  390. <a href="{{ route "export" }}">{{ t "menu.export" }}</a>
  391. </li>
  392. <li>
  393. <a href="{{ route "import" }}">{{ t "menu.import" }}</a>
  394. </li>
  395. </ul>
  396. </section>
  397. {{ if not .categories }}
  398. <p class="alert alert-error">{{ t "page.add_feed.no_category" }}</p>
  399. {{ else }}
  400. {{ if ne .feed.ParsingErrorCount 0 }}
  401. <div class="alert alert-error">
  402. <h3>{{ t "page.edit_feed.last_parsing_error" }}</h3>
  403. <p>{{ t .feed.ParsingErrorMsg }}</p>
  404. </div>
  405. {{ end }}
  406. <form action="{{ route "updateFeed" "feedID" .feed.ID }}" method="post" autocomplete="off">
  407. <input type="hidden" name="csrf" value="{{ .csrf }}">
  408. {{ if .errorMessage }}
  409. <div class="alert alert-error">{{ t .errorMessage }}</div>
  410. {{ end }}
  411. <label for="form-title">{{ t "form.feed.label.title" }}</label>
  412. <input type="text" name="title" id="form-title" value="{{ .form.Title }}" required autofocus>
  413. <label for="form-site-url">{{ t "form.feed.label.site_url" }}</label>
  414. <input type="url" name="site_url" id="form-site-url" placeholder="https://domain.tld/" value="{{ .form.SiteURL }}" required>
  415. <label for="form-feed-url">{{ t "form.feed.label.feed_url" }}</label>
  416. <input type="url" name="feed_url" id="form-feed-url" placeholder="https://domain.tld/" value="{{ .form.FeedURL }}" required>
  417. <label for="form-feed-username">{{ t "form.feed.label.feed_username" }}</label>
  418. <input type="text" name="feed_username" id="form-feed-username" value="{{ .form.Username }}">
  419. <label for="form-feed-password">{{ t "form.feed.label.feed_password" }}</label>
  420. <!--
  421. We are using the type "text" otherwise Firefox always autocomplete this password:
  422. - autocomplete="off" or autocomplete="new-password" doesn't change anything
  423. - Changing the input ID doesn't change anything
  424. - Using a different input name doesn't change anything
  425. -->
  426. <input type="text" name="feed_password" id="form-feed-password" value="{{ .form.Password }}">
  427. <label for="form-user-agent">{{ t "form.feed.label.user_agent" }}</label>
  428. <input type="text" name="user_agent" id="form-user-agent" placeholder="{{ .defaultUserAgent }}" value="{{ .form.UserAgent }}">
  429. <label for="form-scraper-rules">{{ t "form.feed.label.scraper_rules" }}</label>
  430. <input type="text" name="scraper_rules" id="form-scraper-rules" value="{{ .form.ScraperRules }}">
  431. <label for="form-rewrite-rules">{{ t "form.feed.label.rewrite_rules" }}</label>
  432. <input type="text" name="rewrite_rules" id="form-rewrite-rules" value="{{ .form.RewriteRules }}">
  433. <label for="form-category">{{ t "form.feed.label.category" }}</label>
  434. <select id="form-category" name="category_id">
  435. {{ range .categories }}
  436. <option value="{{ .ID }}" {{ if eq .ID $.form.CategoryID }}selected="selected"{{ end }}>{{ .Title }}</option>
  437. {{ end }}
  438. </select>
  439. <label><input type="checkbox" name="crawler" value="1" {{ if .form.Crawler }}checked{{ end }}> {{ t "form.feed.label.crawler" }}</label>
  440. <div class="buttons">
  441. <button type="submit" class="button button-primary" data-label-loading="{{ t "form.submit.saving" }}">{{ t "action.update" }}</button> {{ t "action.or" }} <a href="{{ route "feeds" }}">{{ t "action.cancel" }}</a>
  442. </div>
  443. </form>
  444. <div class="panel">
  445. <ul>
  446. <li><strong>{{ t "page.edit_feed.last_check" }} </strong><time datetime="{{ isodate .feed.CheckedAt }}" title="{{ isodate .feed.CheckedAt }}">{{ elapsed $.user.Timezone .feed.CheckedAt }}</time></li>
  447. <li><strong>{{ t "page.edit_feed.etag_header" }} </strong>{{ if .feed.EtagHeader }}{{ .feed.EtagHeader }}{{ else }}{{ t "page.edit_feed.no_header" }}{{ end }}</li>
  448. <li><strong>{{ t "page.edit_feed.last_modified_header" }} </strong>{{ if .feed.LastModifiedHeader }}{{ .feed.LastModifiedHeader }}{{ else }}{{ t "page.edit_feed.no_header" }}{{ end }}</li>
  449. </ul>
  450. </div>
  451. <div class="alert alert-error">
  452. <a href="#"
  453. data-confirm="true"
  454. data-action="remove-feed"
  455. data-label-question="{{ t "confirm.question" }}"
  456. data-label-yes="{{ t "confirm.yes" }}"
  457. data-label-no="{{ t "confirm.no" }}"
  458. data-label-loading="{{ t "confirm.loading" }}"
  459. data-url="{{ route "removeFeed" "feedID" .feed.ID }}"
  460. data-redirect-url="{{ route "feeds" }}">{{ t "action.remove_feed" }}</a>
  461. </div>
  462. {{ end }}
  463. {{ end }}
  464. `,
  465. "edit_user": `{{ define "title"}}{{ t "page.edit_user.title" .selected_user.Username }}{{ end }}
  466. {{ define "content"}}
  467. <section class="page-header">
  468. <h1>{{ t "page.edit_user.title" .selected_user.Username }}</h1>
  469. <ul>
  470. <li>
  471. <a href="{{ route "settings" }}">{{ t "menu.settings" }}</a>
  472. </li>
  473. <li>
  474. <a href="{{ route "integrations" }}">{{ t "menu.integrations" }}</a>
  475. </li>
  476. <li>
  477. <a href="{{ route "sessions" }}">{{ t "menu.sessions" }}</a>
  478. </li>
  479. <li>
  480. <a href="{{ route "users" }}">{{ t "menu.users" }}</a>
  481. </li>
  482. <li>
  483. <a href="{{ route "createUser" }}">{{ t "menu.add_user" }}</a>
  484. </li>
  485. <li>
  486. <a href="{{ route "about" }}">{{ t "menu.about" }}</a>
  487. </li>
  488. </ul>
  489. </section>
  490. <form action="{{ route "updateUser" "userID" .selected_user.ID }}" method="post" autocomplete="off">
  491. <input type="hidden" name="csrf" value="{{ .csrf }}">
  492. {{ if .errorMessage }}
  493. <div class="alert alert-error">{{ t .errorMessage }}</div>
  494. {{ end }}
  495. <label for="form-username">{{ t "form.user.label.username" }}</label>
  496. <input type="text" name="username" id="form-username" value="{{ .form.Username }}" autocomplete="new-password" required autofocus>
  497. <label for="form-password">{{ t "form.user.label.password" }}</label>
  498. <input type="password" name="password" id="form-password" value="{{ .form.Password }}" autocomplete="new-password">
  499. <label for="form-confirmation">{{ t "form.user.label.confirmation" }}</label>
  500. <input type="password" name="confirmation" id="form-confirmation" value="{{ .form.Confirmation }}" autocomplete="new-password">
  501. <label><input type="checkbox" name="is_admin" value="1" {{ if .form.IsAdmin }}checked{{ end }}> {{ t "form.user.label.admin" }}</label>
  502. <div class="buttons">
  503. <button type="submit" class="button button-primary" data-label-loading="{{ t "form.submit.saving" }}">{{ t "action.update" }}</button> {{ t "action.or" }} <a href="{{ route "users" }}">{{ t "action.cancel" }}</a>
  504. </div>
  505. </form>
  506. {{ end }}
  507. `,
  508. "entry": `{{ define "title"}}{{ .entry.Title }}{{ end }}
  509. {{ define "content"}}
  510. <section class="entry" data-id="{{ .entry.ID }}">
  511. <header class="entry-header">
  512. <h1>
  513. <a href="{{ .entry.URL }}" target="_blank" rel="noopener noreferrer" referrerpolicy="no-referrer">{{ .entry.Title }}</a>
  514. </h1>
  515. <div class="entry-actions">
  516. <ul>
  517. <li>
  518. <a href="#"
  519. title="{{ t "entry.status.title" }}"
  520. data-toggle-status="true"
  521. data-label-read="✔&#xfe0e;&nbsp;{{ t "entry.status.read" }}"
  522. data-label-unread="✘&nbsp;{{ t "entry.status.unread" }}"
  523. data-value="{{ if eq .entry.Status "read" }}read{{ else }}unread{{ end }}"
  524. >{{ if eq .entry.Status "read" }}✘&nbsp;{{ t "entry.status.unread" }}{{ else }}✔&#xfe0e;&nbsp;{{ t "entry.status.read" }}{{ end }}</a>
  525. </li>
  526. <li>
  527. <a href="#"
  528. data-toggle-bookmark="true"
  529. data-bookmark-url="{{ route "toggleBookmark" "entryID" .entry.ID }}"
  530. data-label-loading="{{ t "entry.state.saving" }}"
  531. data-label-star="☆&nbsp;{{ t "entry.bookmark.toggle.on" }}"
  532. data-label-unstar="★&nbsp;{{ t "entry.bookmark.toggle.off" }}"
  533. data-value="{{ if .entry.Starred }}star{{ else }}unstar{{ end }}"
  534. >{{ if .entry.Starred }}★&nbsp;{{ t "entry.bookmark.toggle.off" }}{{ else }}☆&nbsp;{{ t "entry.bookmark.toggle.on" }}{{ end }}</a>
  535. </li>
  536. {{ if .hasSaveEntry }}
  537. <li>
  538. <a href="#"
  539. title="{{ t "entry.save.title" }}"
  540. data-save-entry="true"
  541. data-save-url="{{ route "saveEntry" "entryID" .entry.ID }}"
  542. data-label-loading="{{ t "entry.state.saving" }}"
  543. data-label-done="{{ t "entry.save.completed" }}"
  544. >{{ t "entry.save.title" }}</a>
  545. </li>
  546. {{ end }}
  547. <li>
  548. <a href="#"
  549. title="{{ t "entry.scraper.title" }}"
  550. data-fetch-content-entry="true"
  551. data-fetch-content-url="{{ route "fetchContent" "entryID" .entry.ID }}"
  552. data-label-loading="{{ t "entry.state.loading" }}"
  553. data-label-done="{{ t "entry.scraper.completed" }}"
  554. >{{ t "entry.scraper.label" }}</a>
  555. </li>
  556. {{ if .entry.CommentsURL }}
  557. <li>
  558. <a href="{{ .entry.CommentsURL }}" title="{{ t "entry.comments.title" }}" target="_blank" rel="noopener noreferrer" referrerpolicy="no-referrer">{{ t "entry.comments.label" }}</a>
  559. </li>
  560. {{ end }}
  561. </ul>
  562. </div>
  563. <div class="entry-meta">
  564. <span class="entry-website">
  565. {{ if ne .entry.Feed.Icon.IconID 0 }}
  566. <img src="{{ route "icon" "iconID" .entry.Feed.Icon.IconID }}" width="16" height="16" alt="{{ .entry.Feed.Title }}">
  567. {{ end }}
  568. <a href="{{ route "feedEntries" "feedID" .entry.Feed.ID }}">{{ .entry.Feed.Title }}</a>
  569. </span>
  570. {{ if .entry.Author }}
  571. <span class="entry-author">
  572. {{ if isEmail .entry.Author }}
  573. - <a href="mailto:{{ .entry.Author }}">{{ .entry.Author }}</a>
  574. {{ else }}
  575. – <em>{{ .entry.Author }}</em>
  576. {{ end }}
  577. </span>
  578. {{ end }}
  579. <span class="category">
  580. <a href="{{ route "categoryEntries" "categoryID" .entry.Feed.Category.ID }}">{{ .entry.Feed.Category.Title }}</a>
  581. </span>
  582. </div>
  583. <div class="entry-date">
  584. <time datetime="{{ isodate .entry.Date }}" title="{{ isodate .entry.Date }}">{{ elapsed $.user.Timezone .entry.Date }}</time>
  585. </div>
  586. </header>
  587. {{ if gt (len .entry.Content) 120 }}
  588. <div class="pagination-top">
  589. {{ template "entry_pagination" . }}
  590. </div>
  591. {{ end }}
  592. <article class="entry-content">
  593. {{ noescape (proxyFilter .entry.Content) }}
  594. </article>
  595. {{ if .entry.Enclosures }}
  596. <aside class="entry-enclosures">
  597. <h3>{{ t "page.entry.attachments" }}</h3>
  598. {{ range .entry.Enclosures }}
  599. <div class="entry-enclosure">
  600. {{ if hasPrefix .MimeType "audio/" }}
  601. <div class="enclosure-audio">
  602. <audio controls preload="metadata">
  603. <source src="{{ .URL }}" type="{{ .MimeType }}">
  604. </audio>
  605. </div>
  606. {{ else if hasPrefix .MimeType "video/" }}
  607. <div class="enclosure-video">
  608. <video controls preload="metadata">
  609. <source src="{{ .URL }}" type="{{ .MimeType }}">
  610. </video>
  611. </div>
  612. {{ else if hasPrefix .MimeType "image/" }}
  613. <div class="enclosure-image">
  614. <img src="{{ proxyURL .URL }}" title="{{ .URL }} ({{ .MimeType }})" alt="{{ .URL }} ({{ .MimeType }})">
  615. </div>
  616. {{ end }}
  617. <div class="entry-enclosure-download">
  618. <a href="{{ .URL }}" title="{{ .URL }} ({{ .MimeType }})" target="_blank" rel="noopener noreferrer" referrerpolicy="no-referrer">{{ t "action.download" }}</a>
  619. <small>({{ .URL }})</small>
  620. </div>
  621. </div>
  622. {{ end }}
  623. </aside>
  624. {{ end }}
  625. </section>
  626. <div class="pagination-bottom">
  627. {{ template "entry_pagination" . }}
  628. </div>
  629. {{ end }}
  630. `,
  631. "feed_entries": `{{ define "title"}}{{ .feed.Title }} ({{ .total }}){{ end }}
  632. {{ define "content"}}
  633. <section class="page-header">
  634. <h1>{{ .feed.Title }} ({{ .total }})</h1>
  635. <ul>
  636. {{ if .entries }}
  637. <li>
  638. <a href="#"
  639. data-confirm="true"
  640. data-label-question="{{ t "confirm.question" }}"
  641. data-label-yes="{{ t "confirm.yes" }}"
  642. data-label-no="{{ t "confirm.no" }}"
  643. data-label-loading="{{ t "confirm.loading" }}"
  644. data-show-only-unread="{{ if .showOnlyUnreadEntries }}1{{ end }}"
  645. data-mark-page-as-read="true">
  646. {{ t "menu.mark_page_as_read" }}
  647. </a>
  648. </li>
  649. {{ end }}
  650. {{ if .showOnlyUnreadEntries }}
  651. <li>
  652. <a href="{{ route "feedEntriesAll" "feedID" .feed.ID }}">{{ t "menu.show_all_entries" }}</a>
  653. </li>
  654. {{ else }}
  655. <li>
  656. <a href="{{ route "feedEntries" "feedID" .feed.ID }}">{{ t "menu.show_only_unread_entries" }}</a>
  657. </li>
  658. {{ end }}
  659. <li>
  660. <a href="{{ route "refreshFeed" "feedID" .feed.ID }}">{{ t "menu.refresh_feed" }}</a>
  661. </li>
  662. <li>
  663. <a href="{{ route "editFeed" "feedID" .feed.ID }}">{{ t "menu.edit_feed" }}</a>
  664. </li>
  665. <li>
  666. <a href="#"
  667. data-confirm="true"
  668. data-action="remove-feed"
  669. data-label-question="{{ t "confirm.question" }}"
  670. data-label-yes="{{ t "confirm.yes" }}"
  671. data-label-no="{{ t "confirm.no" }}"
  672. data-label-loading="{{ t "confirm.loading" }}"
  673. data-url="{{ route "removeFeed" "feedID" .feed.ID }}"
  674. data-redirect-url="{{ route "feeds" }}">{{ t "action.remove_feed" }}</a>
  675. </li>
  676. </ul>
  677. </section>
  678. {{ if ne .feed.ParsingErrorCount 0 }}
  679. <div class="alert alert-error">
  680. <h3>{{ t "alert.feed_error" }}</h3>
  681. <p>{{ t .feed.ParsingErrorMsg }}</p>
  682. </div>
  683. {{ end }}
  684. {{ if not .entries }}
  685. {{ if .showOnlyUnreadEntries }}
  686. <p class="alert">{{ t "alert.no_unread_entry" }}</p>
  687. {{ else }}
  688. <p class="alert">{{ t "alert.no_feed_entry" }}</p>
  689. {{ end }}
  690. {{ else }}
  691. <div class="items">
  692. {{ range .entries }}
  693. <article class="item touch-item item-status-{{ .Status }}" data-id="{{ .ID }}">
  694. <div class="item-header">
  695. <span class="item-title">
  696. {{ if ne .Feed.Icon.IconID 0 }}
  697. <img src="{{ route "icon" "iconID" .Feed.Icon.IconID }}" width="16" height="16" alt="{{ .Feed.Title }}">
  698. {{ end }}
  699. <a href="{{ route "feedEntry" "feedID" .Feed.ID "entryID" .ID }}">{{ .Title }}</a>
  700. </span>
  701. <span class="category"><a href="{{ route "categoryEntries" "categoryID" .Feed.Category.ID }}">{{ .Feed.Category.Title }}</a></span>
  702. </div>
  703. {{ template "item_meta" dict "user" $.user "entry" . "hasSaveEntry" $.hasSaveEntry }}
  704. </article>
  705. {{ end }}
  706. </div>
  707. <section class="page-footer">
  708. {{ if .entries }}
  709. <ul>
  710. <li>
  711. <a href="#"
  712. data-confirm="true"
  713. data-label-question="{{ t "confirm.question" }}"
  714. data-label-yes="{{ t "confirm.yes" }}"
  715. data-label-no="{{ t "confirm.no" }}"
  716. data-label-loading="{{ t "confirm.loading" }}"
  717. data-show-only-unread="{{ if .showOnlyUnreadEntries }}1{{ end }}"
  718. data-mark-page-as-read="true">
  719. {{ t "menu.mark_page_as_read" }}
  720. </a>
  721. </li>
  722. </ul>
  723. {{ end }}
  724. </section>
  725. {{ template "pagination" .pagination }}
  726. {{ end }}
  727. {{ end }}
  728. `,
  729. "feeds": `{{ define "title"}}{{ t "page.feeds.title" }} ({{ .total }}){{ end }}
  730. {{ define "content"}}
  731. <section class="page-header">
  732. <h1>{{ t "page.feeds.title" }} ({{ .total }})</h1>
  733. <ul>
  734. <li>
  735. <a href="{{ route "addSubscription" }}">{{ t "menu.add_feed" }}</a>
  736. </li>
  737. <li>
  738. <a href="{{ route "export" }}">{{ t "menu.export" }}</a>
  739. </li>
  740. <li>
  741. <a href="{{ route "import" }}">{{ t "menu.import" }}</a>
  742. </li>
  743. <li>
  744. <a href="{{ route "refreshAllFeeds" }}">{{ t "menu.refresh_all_feeds" }}</a>
  745. </li>
  746. </ul>
  747. </section>
  748. {{ if not .feeds }}
  749. <p class="alert">{{ t "alert.no_feed" }}</p>
  750. {{ else }}
  751. <div class="items">
  752. {{ range .feeds }}
  753. <article class="item {{ if ne .ParsingErrorCount 0 }}feed-parsing-error{{ end }}">
  754. <div class="item-header">
  755. <span class="item-title">
  756. {{ if .Icon }}
  757. <img src="{{ route "icon" "iconID" .Icon.IconID }}" width="16" height="16" alt="{{ .Title }}">
  758. {{ end }}
  759. <a href="{{ route "feedEntries" "feedID" .ID }}">{{ .Title }}</a>
  760. </span>
  761. <span class="category">
  762. <a href="{{ route "categoryEntries" "categoryID" .Category.ID }}">{{ .Category.Title }}</a>
  763. </span>
  764. </div>
  765. <div class="item-meta">
  766. <ul>
  767. <li>
  768. <a href="{{ .SiteURL }}" title="{{ .SiteURL }}" target="_blank" rel="noopener noreferrer" referrerpolicy="no-referrer" data-original-link="true">{{ domain .SiteURL }}</a>
  769. </li>
  770. <li>
  771. {{ t "page.feeds.last_check" }} <time datetime="{{ isodate .CheckedAt }}" title="{{ isodate .CheckedAt }}">{{ elapsed $.user.Timezone .CheckedAt }}</time>
  772. </li>
  773. </ul>
  774. <ul>
  775. <li>
  776. <a href="{{ route "refreshFeed" "feedID" .ID }}">{{ t "menu.refresh_feed" }}</a>
  777. </li>
  778. <li>
  779. <a href="{{ route "editFeed" "feedID" .ID }}">{{ t "menu.edit_feed" }}</a>
  780. </li>
  781. <li>
  782. <a href="#"
  783. data-confirm="true"
  784. data-label-question="{{ t "confirm.question" }}"
  785. data-label-yes="{{ t "confirm.yes" }}"
  786. data-label-no="{{ t "confirm.no" }}"
  787. data-label-loading="{{ t "confirm.loading" }}"
  788. data-url="{{ route "removeFeed" "feedID" .ID }}">{{ t "action.remove" }}</a>
  789. </li>
  790. </ul>
  791. </div>
  792. {{ if ne .ParsingErrorCount 0 }}
  793. <div class="parsing-error">
  794. <strong title="{{ .ParsingErrorMsg }}" class="parsing-error-count">{{ plural "page.feeds.error_count" .ParsingErrorCount .ParsingErrorCount }}</strong>
  795. - <small class="parsing-error-message">{{ .ParsingErrorMsg }}</small>
  796. </div>
  797. {{ end }}
  798. </article>
  799. {{ end }}
  800. </div>
  801. {{ end }}
  802. {{ end }}
  803. `,
  804. "history_entries": `{{ define "title"}}{{ t "page.history.title" }} ({{ .total }}){{ end }}
  805. {{ define "content"}}
  806. <section class="page-header">
  807. <h1>{{ t "page.history.title" }} ({{ .total }})</h1>
  808. {{ if .entries }}
  809. <ul>
  810. <li>
  811. <a href="{{ route "flushHistory" }}">{{ t "menu.flush_history" }}</a>
  812. </li>
  813. </ul>
  814. {{ end }}
  815. </section>
  816. {{ if not .entries }}
  817. <p class="alert alert-info">{{ t "alert.no_history" }}</p>
  818. {{ else }}
  819. <div class="items">
  820. {{ range .entries }}
  821. <article class="item touch-item item-status-{{ .Status }}" data-id="{{ .ID }}">
  822. <div class="item-header">
  823. <span class="item-title">
  824. {{ if ne .Feed.Icon.IconID 0 }}
  825. <img src="{{ route "icon" "iconID" .Feed.Icon.IconID }}" width="16" height="16" alt="{{ .Feed.Title }}">
  826. {{ end }}
  827. <a href="{{ route "readEntry" "entryID" .ID }}">{{ .Title }}</a>
  828. </span>
  829. <span class="category"><a href="{{ route "categoryEntries" "categoryID" .Feed.Category.ID }}">{{ .Feed.Category.Title }}</a></span>
  830. </div>
  831. {{ template "item_meta" dict "user" $.user "entry" . "hasSaveEntry" $.hasSaveEntry }}
  832. </article>
  833. {{ end }}
  834. </div>
  835. {{ template "pagination" .pagination }}
  836. {{ end }}
  837. {{ end }}
  838. `,
  839. "import": `{{ define "title"}}{{ t "page.import.title" }}{{ end }}
  840. {{ define "content"}}
  841. <section class="page-header">
  842. <h1>{{ t "page.import.title" }}</h1>
  843. <ul>
  844. <li>
  845. <a href="{{ route "feeds" }}">{{ t "menu.feeds" }}</a>
  846. </li>
  847. <li>
  848. <a href="{{ route "addSubscription" }}">{{ t "menu.add_feed" }}</a>
  849. </li>
  850. <li>
  851. <a href="{{ route "export" }}">{{ t "menu.export" }}</a>
  852. </li>
  853. </ul>
  854. </section>
  855. <form action="{{ route "uploadOPML" }}" method="post" enctype="multipart/form-data">
  856. <input type="hidden" name="csrf" value="{{ .csrf }}">
  857. {{ if .errorMessage }}
  858. <div class="alert alert-error">{{ t .errorMessage }}</div>
  859. {{ end }}
  860. <label for="form-file">{{ t "form.import.label.file" }}</label>
  861. <input type="file" name="file" id="form-file">
  862. <div class="buttons">
  863. <button type="submit" class="button button-primary" data-label-loading="{{ t "form.submit.saving" }}">{{ t "action.import" }}</button>
  864. </div>
  865. </form>
  866. {{ end }}
  867. `,
  868. "integrations": `{{ define "title"}}{{ t "page.integrations.title" }}{{ end }}
  869. {{ define "content"}}
  870. <section class="page-header">
  871. <h1>{{ t "page.integrations.title" }}</h1>
  872. <ul>
  873. <li>
  874. <a href="{{ route "settings" }}">{{ t "menu.settings" }}</a>
  875. </li>
  876. <li>
  877. <a href="{{ route "sessions" }}">{{ t "menu.sessions" }}</a>
  878. </li>
  879. {{ if .user.IsAdmin }}
  880. <li>
  881. <a href="{{ route "users" }}">{{ t "menu.users" }}</a>
  882. </li>
  883. {{ end }}
  884. <li>
  885. <a href="{{ route "about" }}">{{ t "menu.about" }}</a>
  886. </li>
  887. </ul>
  888. </section>
  889. <form method="post" autocomplete="off" action="{{ route "updateIntegration" }}">
  890. <input type="hidden" name="csrf" value="{{ .csrf }}">
  891. {{ if .errorMessage }}
  892. <div class="alert alert-error">{{ t .errorMessage }}</div>
  893. {{ end }}
  894. <h3>Fever</h3>
  895. <div class="form-section">
  896. <label>
  897. <input type="checkbox" name="fever_enabled" value="1" {{ if .form.FeverEnabled }}checked{{ end }}> {{ t "form.integration.fever_activate" }}
  898. </label>
  899. <label for="form-fever-username">{{ t "form.integration.fever_username" }}</label>
  900. <input type="text" name="fever_username" id="form-fever-username" value="{{ .form.FeverUsername }}">
  901. <label for="form-fever-password">{{ t "form.integration.fever_password" }}</label>
  902. <input type="password" name="fever_password" id="form-fever-password" value="{{ .form.FeverPassword }}" autocomplete="new-password">
  903. <p>{{ t "form.integration.fever_endpoint" }} <strong>{{ rootURL }}{{ route "feverEndpoint" }}</strong></p>
  904. </div>
  905. <h3>Pinboard</h3>
  906. <div class="form-section">
  907. <label>
  908. <input type="checkbox" name="pinboard_enabled" value="1" {{ if .form.PinboardEnabled }}checked{{ end }}> {{ t "form.integration.pinboard_activate" }}
  909. </label>
  910. <label for="form-pinboard-token">{{ t "form.integration.pinboard_token" }}</label>
  911. <input type="password" name="pinboard_token" id="form-pinboard-token" value="{{ .form.PinboardToken }}" autocomplete="new-password">
  912. <label for="form-pinboard-tags">{{ t "form.integration.pinboard_tags" }}</label>
  913. <input type="text" name="pinboard_tags" id="form-pinboard-tags" value="{{ .form.PinboardTags }}">
  914. <label>
  915. <input type="checkbox" name="pinboard_mark_as_unread" value="1" {{ if .form.PinboardMarkAsUnread }}checked{{ end }}> {{ t "form.integration.pinboard_bookmark" }}
  916. </label>
  917. </div>
  918. <h3>Instapaper</h3>
  919. <div class="form-section">
  920. <label>
  921. <input type="checkbox" name="instapaper_enabled" value="1" {{ if .form.InstapaperEnabled }}checked{{ end }}> {{ t "form.integration.instapaper_activate" }}
  922. </label>
  923. <label for="form-instapaper-username">{{ t "form.integration.instapaper_username" }}</label>
  924. <input type="text" name="instapaper_username" id="form-instapaper-username" value="{{ .form.InstapaperUsername }}">
  925. <label for="form-instapaper-password">{{ t "form.integration.instapaper_password" }}</label>
  926. <input type="password" name="instapaper_password" id="form-instapaper-password" value="{{ .form.InstapaperPassword }}" autocomplete="new-password">
  927. </div>
  928. <h3>Pocket</h3>
  929. <div class="form-section">
  930. <label>
  931. <input type="checkbox" name="pocket_enabled" value="1" {{ if .form.PocketEnabled }}checked{{ end }}> {{ t "form.integration.pocket_activate" }}
  932. </label>
  933. {{ if not .hasPocketConsumerKeyConfigured }}
  934. <label for="form-pocket-consumer-key">{{ t "form.integration.pocket_consumer_key" }}</label>
  935. <input type="text" name="pocket_consumer_key" id="form-pocket-consumer-key" value="{{ .form.PocketConsumerKey }}">
  936. {{ end }}
  937. <label for="form-pocket-access-token">{{ t "form.integration.pocket_access_token" }}</label>
  938. <input type="password" name="pocket_access_token" id="form-pocket-access-token" value="{{ .form.PocketAccessToken }}" autocomplete="new-password">
  939. {{ if not .form.PocketAccessToken }}
  940. <p><a href="{{ route "pocketAuthorize" }}">{{ t "form.integration.pocket_connect_link" }}</a></p>
  941. {{ end }}
  942. </div>
  943. <h3>Wallabag</h3>
  944. <div class="form-section">
  945. <label>
  946. <input type="checkbox" name="wallabag_enabled" value="1" {{ if .form.WallabagEnabled }}checked{{ end }}> {{ t "form.integration.wallabag_activate" }}
  947. </label>
  948. <label for="form-wallabag-url">{{ t "form.integration.wallabag_endpoint" }}</label>
  949. <input type="url" name="wallabag_url" id="form-wallabag-url" value="{{ .form.WallabagURL }}" placeholder="http://v2.wallabag.org/">
  950. <label for="form-wallabag-client-id">{{ t "form.integration.wallabag_client_id" }}</label>
  951. <input type="text" name="wallabag_client_id" id="form-wallabag-client-id" value="{{ .form.WallabagClientID }}">
  952. <label for="form-wallabag-client-secret">{{ t "form.integration.wallabag_client_secret" }}</label>
  953. <input type="password" name="wallabag_client_secret" id="form-wallabag-client-secret" value="{{ .form.WallabagClientSecret }}" autocomplete="new-password">
  954. <label for="form-wallabag-username">{{ t "form.integration.wallabag_username" }}</label>
  955. <input type="text" name="wallabag_username" id="form-wallabag-username" value="{{ .form.WallabagUsername }}">
  956. <label for="form-wallabag-password">{{ t "form.integration.wallabag_password" }}</label>
  957. <input type="password" name="wallabag_password" id="form-wallabag-password" value="{{ .form.WallabagPassword }}" autocomplete="new-password">
  958. </div>
  959. <h3>Nunux Keeper</h3>
  960. <div class="form-section">
  961. <label>
  962. <input type="checkbox" name="nunux_keeper_enabled" value="1" {{ if .form.NunuxKeeperEnabled }}checked{{ end }}> {{ t "form.integration.nunux_keeper_activate" }}
  963. </label>
  964. <label for="form-nunux-keeper-url">{{ t "form.integration.nunux_keeper_endpoint" }}</label>
  965. <input type="url" name="nunux_keeper_url" id="form-nunux-keeper-url" value="{{ .form.NunuxKeeperURL }}" placeholder="https://api.nunux.org/keeper">
  966. <label for="form-nunux-keeper-api-key">{{ t "form.integration.nunux_keeper_api_key" }}</label>
  967. <input type="text" name="nunux_keeper_api_key" id="form-nunux-keeper-api-key" value="{{ .form.NunuxKeeperAPIKey }}">
  968. </div>
  969. <div class="buttons">
  970. <button type="submit" class="button button-primary" data-label-loading="{{ t "form.submit.saving" }}">{{ t "action.update" }}</button>
  971. </div>
  972. </form>
  973. <h3>{{ t "page.integration.miniflux_api" }}</h3>
  974. <div class="panel">
  975. <ul>
  976. <li>
  977. {{ t "page.integration.miniflux_api_endpoint" }} = <strong>{{ baseURL }}/v1/</strong>
  978. </li>
  979. <li>
  980. {{ t "page.integration.miniflux_api_username" }} = <strong>{{ .user.Username }}</strong>
  981. </li>
  982. <li>
  983. {{ t "page.integration.miniflux_api_password" }} = <strong>{{ t "page.integration.miniflux_api_password_value" }}</strong>
  984. </li>
  985. </ul>
  986. </div>
  987. <h3>{{ t "page.integration.bookmarklet" }}</h3>
  988. <div class="panel">
  989. <p>{{ t "page.integration.bookmarklet.help" }}</p>
  990. <div class="bookmarklet">
  991. <a href="javascript:location.href='{{ rootURL }}{{ route "bookmarklet" }}?uri='+encodeURIComponent(window.location.href)">{{ t "page.integration.bookmarklet.name" }}</a>
  992. </div>
  993. <p>{{ t "page.integration.bookmarklet.instructions" }}</p>
  994. </div>
  995. {{ end }}
  996. `,
  997. "login": `{{ define "title"}}{{ t "page.login.title" }}{{ end }}
  998. {{ define "content"}}
  999. <section class="login-form">
  1000. <form action="{{ route "checkLogin" }}" method="post">
  1001. <input type="hidden" name="csrf" value="{{ .csrf }}">
  1002. {{ if .errorMessage }}
  1003. <div class="alert alert-error">{{ t .errorMessage }}</div>
  1004. {{ end }}
  1005. <label for="form-username">{{ t "form.user.label.username" }}</label>
  1006. <input type="text" name="username" id="form-username" value="{{ .form.Username }}" required autofocus>
  1007. <label for="form-password">{{ t "form.user.label.password" }}</label>
  1008. <input type="password" name="password" id="form-password" value="{{ .form.Password }}" required>
  1009. <div class="buttons">
  1010. <button type="submit" class="button button-primary" data-label-loading="{{ t "form.submit.loading" }}">{{ t "action.login" }}</button>
  1011. </div>
  1012. </form>
  1013. {{ if hasOAuth2Provider "google" }}
  1014. <div class="oauth2">
  1015. <a href="{{ route "oauth2Redirect" "provider" "google" }}">{{ t "page.login.google_signin" }}</a>
  1016. </div>
  1017. {{ end }}
  1018. </section>
  1019. {{ end }}
  1020. `,
  1021. "search_entries": `{{ define "title"}}{{ t "page.search.title" }} ({{ .total }}){{ end }}
  1022. {{ define "content"}}
  1023. <section class="page-header">
  1024. <h1>{{ t "page.search.title" }} ({{ .total }})</h1>
  1025. </section>
  1026. {{ if not .entries }}
  1027. <p class="alert alert-info">{{ t "alert.no_search_result" }}</p>
  1028. {{ else }}
  1029. <div class="items">
  1030. {{ range .entries }}
  1031. <article class="item touch-item item-status-{{ .Status }}" data-id="{{ .ID }}">
  1032. <div class="item-header">
  1033. <span class="item-title">
  1034. {{ if ne .Feed.Icon.IconID 0 }}
  1035. <img src="{{ route "icon" "iconID" .Feed.Icon.IconID }}" width="16" height="16" alt="{{ .Feed.Title }}">
  1036. {{ end }}
  1037. <a href="{{ route "searchEntry" "entryID" .ID }}?q={{ $.searchQuery }}">{{ .Title }}</a>
  1038. </span>
  1039. <span class="category"><a href="{{ route "categoryEntries" "categoryID" .Feed.Category.ID }}">{{ .Feed.Category.Title }}</a></span>
  1040. </div>
  1041. {{ template "item_meta" dict "user" $.user "entry" . "hasSaveEntry" $.hasSaveEntry }}
  1042. </article>
  1043. {{ end }}
  1044. </div>
  1045. {{ template "pagination" .pagination }}
  1046. {{ end }}
  1047. {{ end }}
  1048. `,
  1049. "sessions": `{{ define "title"}}{{ t "page.sessions.title" }}{{ end }}
  1050. {{ define "content"}}
  1051. <section class="page-header">
  1052. <h1>{{ t "page.sessions.title" }}</h1>
  1053. <ul>
  1054. <li>
  1055. <a href="{{ route "settings" }}">{{ t "menu.settings" }}</a>
  1056. </li>
  1057. <li>
  1058. <a href="{{ route "integrations" }}">{{ t "menu.integrations" }}</a>
  1059. </li>
  1060. {{ if .user.IsAdmin }}
  1061. <li>
  1062. <a href="{{ route "users" }}">{{ t "menu.users" }}</a>
  1063. </li>
  1064. <li>
  1065. <a href="{{ route "createUser" }}">{{ t "menu.add_user" }}</a>
  1066. </li>
  1067. {{ end }}
  1068. <li>
  1069. <a href="{{ route "about" }}">{{ t "menu.about" }}</a>
  1070. </li>
  1071. </ul>
  1072. </section>
  1073. <table>
  1074. <tr>
  1075. <th>{{ t "page.sessions.table.date" }}</th>
  1076. <th>{{ t "page.sessions.table.ip" }}</th>
  1077. <th>{{ t "page.sessions.table.user_agent" }}</th>
  1078. <th>{{ t "page.sessions.table.actions" }}</th>
  1079. </tr>
  1080. {{ range .sessions }}
  1081. <tr {{ if eq .Token $.currentSessionToken }}class="row-highlighted"{{ end }}>
  1082. <td class="column-20" title="{{ isodate .CreatedAt }}">{{ elapsed $.user.Timezone .CreatedAt }}</td>
  1083. <td class="column-20" title="{{ .IP }}">{{ .IP }}</td>
  1084. <td title="{{ .UserAgent }}">{{ .UserAgent }}</td>
  1085. <td class="column-20">
  1086. {{ if eq .Token $.currentSessionToken }}
  1087. {{ t "page.sessions.table.current_session" }}
  1088. {{ else }}
  1089. <a href="#"
  1090. data-confirm="true"
  1091. data-label-question="{{ t "confirm.question" }}"
  1092. data-label-yes="{{ t "confirm.yes" }}"
  1093. data-label-no="{{ t "confirm.no" }}"
  1094. data-label-loading="{{ t "confirm.loading" }}"
  1095. data-url="{{ route "removeSession" "sessionID" .ID }}">{{ t "action.remove" }}</a>
  1096. {{ end }}
  1097. </td>
  1098. </tr>
  1099. {{ end }}
  1100. </table>
  1101. {{ end }}
  1102. `,
  1103. "settings": `{{ define "title"}}{{ t "page.settings.title" }}{{ end }}
  1104. {{ define "content"}}
  1105. <section class="page-header">
  1106. <h1>{{ t "page.settings.title" }}</h1>
  1107. <ul>
  1108. <li>
  1109. <a href="{{ route "integrations" }}">{{ t "menu.integrations" }}</a>
  1110. </li>
  1111. <li>
  1112. <a href="{{ route "sessions" }}">{{ t "menu.sessions" }}</a>
  1113. </li>
  1114. {{ if .user.IsAdmin }}
  1115. <li>
  1116. <a href="{{ route "users" }}">{{ t "menu.users" }}</a>
  1117. </li>
  1118. {{ end }}
  1119. <li>
  1120. <a href="{{ route "about" }}">{{ t "menu.about" }}</a>
  1121. </li>
  1122. </ul>
  1123. </section>
  1124. <form method="post" autocomplete="off" action="{{ route "updateSettings" }}">
  1125. <input type="hidden" name="csrf" value="{{ .csrf }}">
  1126. {{ if .errorMessage }}
  1127. <div class="alert alert-error">{{ t .errorMessage }}</div>
  1128. {{ end }}
  1129. <label for="form-username">{{ t "form.user.label.username" }}</label>
  1130. <input type="text" name="username" id="form-username" value="{{ .form.Username }}" required>
  1131. <label for="form-password">{{ t "form.user.label.password" }}</label>
  1132. <input type="password" name="password" id="form-password" value="{{ .form.Password }}" autocomplete="new-password">
  1133. <label for="form-confirmation">{{ t "form.user.label.confirmation" }}</label>
  1134. <input type="password" name="confirmation" id="form-confirmation" value="{{ .form.Confirmation }}" autocomplete="new-password">
  1135. <label for="form-language">{{ t "form.prefs.label.language" }}</label>
  1136. <select id="form-language" name="language">
  1137. {{ range $key, $value := .languages }}
  1138. <option value="{{ $key }}" {{ if eq $key $.form.Language }}selected="selected"{{ end }}>{{ $value }}</option>
  1139. {{ end }}
  1140. </select>
  1141. <label for="form-timezone">{{ t "form.prefs.label.timezone" }}</label>
  1142. <select id="form-timezone" name="timezone">
  1143. {{ range $key, $value := .timezones }}
  1144. <option value="{{ $key }}" {{ if eq $key $.form.Timezone }}selected="selected"{{ end }}>{{ $value }}</option>
  1145. {{ end }}
  1146. </select>
  1147. <label for="form-theme">{{ t "form.prefs.label.theme" }}</label>
  1148. <select id="form-theme" name="theme">
  1149. {{ range $key, $value := .themes }}
  1150. <option value="{{ $key }}" {{ if eq $key $.form.Theme }}selected="selected"{{ end }}>{{ $value }}</option>
  1151. {{ end }}
  1152. </select>
  1153. <label for="form-entry-direction">{{ t "form.prefs.label.entry_sorting" }}</label>
  1154. <select id="form-entry-direction" name="entry_direction">
  1155. <option value="asc" {{ if eq "asc" $.form.EntryDirection }}selected="selected"{{ end }}>{{ t "form.prefs.select.older_first" }}</option>
  1156. <option value="desc" {{ if eq "desc" $.form.EntryDirection }}selected="selected"{{ end }}>{{ t "form.prefs.select.recent_first" }}</option>
  1157. </select>
  1158. <label><input type="checkbox" name="keyboard_shortcuts" value="1" {{ if .form.KeyboardShortcuts }}checked{{ end }}> {{ t "form.prefs.label.keyboard_shortcuts" }}</label>
  1159. <div class="buttons">
  1160. <button type="submit" class="button button-primary" data-label-loading="{{ t "form.submit.saving" }}">{{ t "action.update" }}</button>
  1161. </div>
  1162. </form>
  1163. {{ if hasOAuth2Provider "google" }}
  1164. <div class="panel">
  1165. {{ if hasKey .user.Extra "google_id" }}
  1166. <a href="{{ route "oauth2Unlink" "provider" "google" }}">{{ t "page.settings.unlink_google_account" }}</a>
  1167. {{ else }}
  1168. <a href="{{ route "oauth2Redirect" "provider" "google" }}">{{ t "page.settings.link_google_account" }}</a>
  1169. {{ end }}
  1170. </div>
  1171. {{ end }}
  1172. {{ end }}
  1173. `,
  1174. "unread_entries": `{{ define "title"}}{{ t "page.unread.title" }} {{ if gt .countUnread 0 }}({{ .countUnread }}){{ end }} {{ end }}
  1175. {{ define "content"}}
  1176. <section class="page-header">
  1177. <h1>{{ t "page.unread.title" }} (<span class="unread-counter">{{ .countUnread }}</span>)</h1>
  1178. {{ if .entries }}
  1179. <ul>
  1180. <li>
  1181. <a href="#"
  1182. data-confirm="true"
  1183. data-label-question="{{ t "confirm.question" }}"
  1184. data-label-yes="{{ t "confirm.yes" }}"
  1185. data-label-no="{{ t "confirm.no" }}"
  1186. data-label-loading="{{ t "confirm.loading" }}"
  1187. data-mark-page-as-read="true">
  1188. {{ t "menu.mark_page_as_read" }}
  1189. </a>
  1190. </li>
  1191. <li>
  1192. <a data-link-state="flip"
  1193. data-label-new-state="{{ t "menu.mark_all_as_read_wip" }}"
  1194. href="{{ route "markAllAsRead" }}">{{ t "menu.mark_all_as_read" }}</a>
  1195. </li>
  1196. </ul>
  1197. {{ end }}
  1198. </section>
  1199. {{ if not .entries }}
  1200. <p class="alert">{{ t "alert.no_unread_entry" }}</p>
  1201. {{ else }}
  1202. <div class="items hide-read-items">
  1203. {{ range .entries }}
  1204. <article class="item touch-item item-status-{{ .Status }}" data-id="{{ .ID }}">
  1205. <div class="item-header">
  1206. <span class="item-title">
  1207. {{ if ne .Feed.Icon.IconID 0 }}
  1208. <img src="{{ route "icon" "iconID" .Feed.Icon.IconID }}" width="16" height="16" alt="{{ .Feed.Title }}">
  1209. {{ end }}
  1210. <a href="{{ route "unreadEntry" "entryID" .ID }}">{{ .Title }}</a>
  1211. </span>
  1212. <span class="category"><a href="{{ route "categoryEntries" "categoryID" .Feed.Category.ID }}">{{ .Feed.Category.Title }}</a></span>
  1213. </div>
  1214. {{ template "item_meta" dict "user" $.user "entry" . "hasSaveEntry" $.hasSaveEntry }}
  1215. </article>
  1216. {{ end }}
  1217. </div>
  1218. <section class="page-footer">
  1219. {{ if .entries }}
  1220. <ul>
  1221. <li>
  1222. <a href="#"
  1223. data-confirm="true"
  1224. data-label-question="{{ t "confirm.question" }}"
  1225. data-label-yes="{{ t "confirm.yes" }}"
  1226. data-label-no="{{ t "confirm.no" }}"
  1227. data-label-loading="{{ t "confirm.loading" }}"
  1228. data-mark-page-as-read="true">
  1229. {{ t "menu.mark_page_as_read" }}
  1230. </a>
  1231. </li>
  1232. </ul>
  1233. {{ end }}
  1234. </section>
  1235. {{ template "pagination" .pagination }}
  1236. {{ end }}
  1237. {{ end }}`,
  1238. "users": `{{ define "title"}}{{ t "page.users.title" }}{{ end }}
  1239. {{ define "content"}}
  1240. <section class="page-header">
  1241. <h1>{{ t "page.users.title" }}</h1>
  1242. <ul>
  1243. <li>
  1244. <a href="{{ route "settings" }}">{{ t "menu.settings" }}</a>
  1245. </li>
  1246. <li>
  1247. <a href="{{ route "integrations" }}">{{ t "menu.integrations" }}</a>
  1248. </li>
  1249. <li>
  1250. <a href="{{ route "sessions" }}">{{ t "menu.sessions" }}</a>
  1251. </li>
  1252. <li>
  1253. <a href="{{ route "createUser" }}">{{ t "menu.add_user" }}</a>
  1254. </li>
  1255. <li>
  1256. <a href="{{ route "about" }}">{{ t "menu.about" }}</a>
  1257. </li>
  1258. </ul>
  1259. </section>
  1260. {{ if eq (len .users) 1 }}
  1261. <p class="alert">{{ t "alert.no_user" }}</p>
  1262. {{ else }}
  1263. <table>
  1264. <tr>
  1265. <th class="column-20">{{ t "page.users.username" }}</th>
  1266. <th>{{ t "page.users.is_admin" }}</th>
  1267. <th>{{ t "page.users.last_login" }}</th>
  1268. <th>{{ t "page.users.actions" }}</th>
  1269. </tr>
  1270. {{ range .users }}
  1271. {{ if ne .ID $.user.ID }}
  1272. <tr>
  1273. <td>{{ .Username }}</td>
  1274. <td>{{ if eq .IsAdmin true }}{{ t "page.users.admin.yes" }}{{ else }}{{ t "page.users.admin.no" }}{{ end }}</td>
  1275. <td>
  1276. {{ if .LastLoginAt }}
  1277. <time datetime="{{ isodate .LastLoginAt }}" title="{{ isodate .LastLoginAt }}">{{ elapsed $.user.Timezone .LastLoginAt }}</time>
  1278. {{ else }}
  1279. {{ t "page.users.never_logged" }}
  1280. {{ end }}
  1281. </td>
  1282. <td>
  1283. <a href="{{ route "editUser" "userID" .ID }}">{{ t "action.edit" }}</a>,
  1284. <a href="#"
  1285. data-confirm="true"
  1286. data-label-question="{{ t "confirm.question" }}"
  1287. data-label-yes="{{ t "confirm.yes" }}"
  1288. data-label-no="{{ t "confirm.no" }}"
  1289. data-label-loading="{{ t "confirm.loading" }}"
  1290. data-url="{{ route "removeUser" "userID" .ID }}">{{ t "action.remove" }}</a>
  1291. </td>
  1292. </tr>
  1293. {{ end }}
  1294. {{ end }}
  1295. </table>
  1296. {{ end }}
  1297. {{ end }}
  1298. `,
  1299. }
  1300. var templateViewsMapChecksums = map[string]string{
  1301. "about": "844e3313c33ae31a74b904f6ef5d60299773620d8450da6f760f9f317217c51e",
  1302. "add_subscription": "a0f1d2bc02b6adc83dbeae593f74d9b936102cd6dd73302cdbec2137cafdcdd9",
  1303. "bookmark_entries": "609f4b2342152fe495a219a32f17a4528b01807d61f53cee0cbebf728be73c42",
  1304. "categories": "642ee3cddbd825ee6ab5a77caa0d371096b55de0f1bd4ae3055b8c8a70507d8d",
  1305. "category_entries": "a1a2ed91cb87d5501a7df55db4c05adfb8aca9f1991b466ab2f30cf5bdb5825d",
  1306. "choose_subscription": "33c04843d7c1b608d034e605e52681822fc6d79bc6b900c04915dd9ebae584e2",
  1307. "create_category": "6b22b5ce51abf4e225e23a79f81be09a7fb90acb265e93a8faf9446dff74018d",
  1308. "create_user": "1e940be3afefc0a5c6273bbadcddc1e29811e9548e5227ac2adfe697ca5ce081",
  1309. "edit_category": "daf073d2944a180ce5aaeb80b597eb69597a50dff55a9a1d6cf7938b48d768cb",
  1310. "edit_feed": "ab30c31a4385a7b16c54baa78bdcb93a57181ed1c5018ce097d7eb50673bb995",
  1311. "edit_user": "f4f99412ba771cfca2a2a42778b023b413c5494e9a287053ba8cf380c2865c5f",
  1312. "entry": "1626bf4dd3223b2f730865676162aa0a9f0a0e009cdea90f705230542922e0f4",
  1313. "feed_entries": "96386f3ecb0080f89febbcd6489ad5f8ace3aac61066e94fb70d11462b02c143",
  1314. "feeds": "31acc253c547a6cce5710d72a6f6b3b396162ecd5e5af295b2cf47c1ff55bd06",
  1315. "history_entries": "b65ca1d85615caa7c314a33f1cb997aa3477a79e66b9894b2fd387271ad467d2",
  1316. "import": "8349e47a783bb40d8e9248b4771656e5f006185e11079e1c4680dd52633420ed",
  1317. "integrations": "f85b4a48ab1fc13b8ca94bfbbc44bd5e8784f35b26a63ec32cbe82b96b45e008",
  1318. "login": "2e72d2d4b9786641b696bedbed5e10b04bdfd68254ddbbdb0a53cca621d200c7",
  1319. "search_entries": "d71849a4f2b0573c7c76ad0ea941812009e9f022de60895987a781d3e6f08a01",
  1320. "sessions": "1b3ec0970a4111b81f86d6ed187bb410f88972e2ede6723b9febcc4c7e5fc921",
  1321. "settings": "152143e58d057ea6ab3bfd8dd947bfd70685843ca40e40542484b23849746df4",
  1322. "unread_entries": "9bfe0223d4dc9b6179e4d35758be644138d7b1e28616ddc1f9df6efab6061ab2",
  1323. "users": "4b56cc76fbcc424e7c870d0efca93bb44dbfcc2a08b685cf799c773fbb8dfb2f",
  1324. }