Compare commits

...

287 Commits

Author SHA1 Message Date
Frédéric Guillot 369c988576 Update ChangeLog 2023-08-20 21:41:30 -07:00
jgbresson 691f56fde9 Update rules.go for webtoons.com
Include author text
2023-08-18 16:53:14 -07:00
dependabot[bot] b2467fdd50 Bump github.com/yuin/goldmark from 1.5.5 to 1.5.6
Bumps [github.com/yuin/goldmark](https://github.com/yuin/goldmark) from 1.5.5 to 1.5.6.
- [Release notes](https://github.com/yuin/goldmark/releases)
- [Commits](https://github.com/yuin/goldmark/compare/v1.5.5...v1.5.6)

---
updated-dependencies:
- dependency-name: github.com/yuin/goldmark
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-17 20:32:15 -07:00
Frédéric Guillot 5e520ca5bf Use stdlib HTTP client for third-party integrations 2023-08-14 21:49:02 -07:00
Frédéric Guillot e5d9f2f5a0 Rename internal url package to avoid overlap with net/url 2023-08-13 19:57:04 -07:00
Frédéric Guillot 9f465fd70d Add Shaarli integration 2023-08-13 18:51:50 -07:00
Frédéric Guillot 28df0b119e Add Shiori integration 2023-08-13 13:32:05 -07:00
Frédéric Guillot 13d9d86acd Consider base path when generating third-party services API endpoint 2023-08-12 23:07:52 -07:00
Romain de Laage fb8737e330 feat: use podcast duration tag as reading time 2023-08-12 18:14:29 -07:00
Frédéric Guillot 168a870c02 Move internal packages to an internal folder
For reference: https://go.dev/doc/go1.4#internalpackages
2023-08-10 20:29:34 -07:00
Frédéric Guillot c234903255 Rename Miniflux package name to follow Go module naming convention
For reference: https://go.dev/ref/mod#major-version-suffixes
2023-08-09 22:10:44 -07:00
Frédéric Guillot c980dfe434 Update RockyLinux image from 8 to 9
Closes #2010
2023-08-09 21:11:38 -07:00
njzy 79c91d71c8 feat: support force refresh in feed edit and feed entries page 2023-08-09 20:17:27 -07:00
Kierán Meinhardt 3060946cc1 Use Odysee video duration as read time
This feature works by scraping the Odysee website.

To enable it, set the FETCH_ODYSEE_WATCH_TIME environment variable to
1.
2023-08-09 20:12:05 -07:00
Frédéric Guillot 859b4466ab Upgrade to Go 1.21 2023-08-09 20:02:37 -07:00
dependabot[bot] 124b770ff6 Bump golang.org/x/oauth2 from 0.10.0 to 0.11.0
Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.10.0 to 0.11.0.
- [Commits](https://github.com/golang/oauth2/compare/v0.10.0...v0.11.0)

---
updated-dependencies:
- dependency-name: golang.org/x/oauth2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-07 21:28:56 -07:00
dependabot[bot] 6b6e60ee0d Bump golang.org/x/crypto from 0.11.0 to 0.12.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.11.0 to 0.12.0.
- [Commits](https://github.com/golang/crypto/compare/v0.11.0...v0.12.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-04 17:24:28 -07:00
dependabot[bot] 10aa20e9cd Bump golang.org/x/net from 0.12.0 to 0.13.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.12.0 to 0.13.0.
- [Commits](https://github.com/golang/net/compare/v0.12.0...v0.13.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-01 19:43:17 -07:00
Frédéric Guillot 97c68ce55a Use details disclosure element to show the list of third-party services 2023-07-31 21:40:44 -07:00
Jean Khawand 061f12fbb0 Use Web Share API for sharing entry 2023-07-31 21:11:39 -07:00
Jean Khawand bf4823bdbd Add Apprise integration 2023-07-31 20:55:17 -07:00
Jean Khawand da0198cc0d fix(date-parser): failed to parse date "Fri, 31 Mar 2023 20:19:00 America/Los_Angeles" by adding timezone to invalidTimezoneReplacer
test(date-parser): add TestParseRSSDateTimezone unit test
2023-07-31 19:30:35 -07:00
dependabot[bot] 31538c57a4 Bump github.com/tdewolff/minify/v2 from 2.12.7 to 2.12.8
Bumps [github.com/tdewolff/minify/v2](https://github.com/tdewolff/minify) from 2.12.7 to 2.12.8.
- [Release notes](https://github.com/tdewolff/minify/releases)
- [Commits](https://github.com/tdewolff/minify/compare/v2.12.7...v2.12.8)

---
updated-dependencies:
- dependency-name: github.com/tdewolff/minify/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-31 19:28:42 -07:00
Frédéric Guillot 955650d1e3 Move Thunder Client API collection to contrib folder 2023-07-30 18:59:01 -07:00
Frédéric Guillot e7ccf0aa1e Add SaveEntry function to API client 2023-07-30 15:52:49 -07:00
dependabot[bot] e2fb77bd85 Bump github.com/mccutchen/go-httpbin/v2 from 2.10.0 to 2.11.0
Bumps [github.com/mccutchen/go-httpbin/v2](https://github.com/mccutchen/go-httpbin) from 2.10.0 to 2.11.0.
- [Release notes](https://github.com/mccutchen/go-httpbin/releases)
- [Commits](https://github.com/mccutchen/go-httpbin/compare/v2.10.0...v2.11.0)

---
updated-dependencies:
- dependency-name: github.com/mccutchen/go-httpbin/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-28 16:51:48 -07:00
Jean Khawand de8ceb21ea Add new API endpoint: /entries/{entryID}/save 2023-07-28 13:56:59 -07:00
Corey McCaffrey 3bac768cda Added integration for Readwise Reader 2023-07-27 20:51:44 -07:00
Frédéric Guillot 3aad650622 Trigger Docker and packages workflows only for semantic tags
Go module versioning expect Git tags to start with the letter v.

The goal is to keep the existing naming convention for generated
artifacts and have proper versioning for the Go module.
2023-07-26 20:42:08 -07:00
dependabot[bot] d4fbaaed0c Bump github.com/yuin/goldmark from 1.5.4 to 1.5.5
Bumps [github.com/yuin/goldmark](https://github.com/yuin/goldmark) from 1.5.4 to 1.5.5.
- [Release notes](https://github.com/yuin/goldmark/releases)
- [Commits](https://github.com/yuin/goldmark/compare/v1.5.4...v1.5.5)

---
updated-dependencies:
- dependency-name: github.com/yuin/goldmark
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-24 19:35:23 -07:00
Frédéric Guillot 4a4c309da0 Update ChangeLog 2023-07-21 18:07:13 -07:00
Frédéric Guillot 5e76c797c2 Update issue templates 2023-07-14 20:25:23 -07:00
David Izquierdo 4fdef7b837 Add scrape and rewrite rules for webtoons
Although the only source I have for the rewrite rule is, in fact, https://github.com/miniflux/v2/pull/892, it does work when combined with add_dynamic_image and scraping the right element. I have not investigated further.

Works around https://github.com/miniflux/v2/issues/775 and https://github.com/miniflux/v2/issues/1871 (as in, gives us working webtoons feeds but referer spoofing would still be a nice tool to have).

Fixes https://github.com/miniflux/v2/issues/256.
2023-07-10 21:25:48 -07:00
Frédéric Guillot 7988241e11 Fix regression in integration page and simplify SQL query 2023-07-10 21:07:05 -07:00
Frédéric Guillot 309e6d1084 Wallabag integration: add more information in error message 2023-07-10 19:51:04 -07:00
dependabot[bot] 92bb040640 Bump github.com/mccutchen/go-httpbin/v2 from 2.9.2 to 2.10.0
Bumps [github.com/mccutchen/go-httpbin/v2](https://github.com/mccutchen/go-httpbin) from 2.9.2 to 2.10.0.
- [Release notes](https://github.com/mccutchen/go-httpbin/releases)
- [Commits](https://github.com/mccutchen/go-httpbin/compare/v2.9.2...v2.10.0)

---
updated-dependencies:
- dependency-name: github.com/mccutchen/go-httpbin/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-10 19:22:31 -07:00
Igor Rzegocki 9b42d0e25e feat: support for custom youtube embed URL 2023-07-07 15:59:23 -07:00
Frédéric Guillot f286c3c1c9 Keep styling backward compatible 2023-07-07 15:44:44 -07:00
Tuukka Ojala e16870a638 Fix incorrect return value comparisons 2023-07-07 15:44:44 -07:00
Tuukka Ojala f0eb6b2688 Fix code formatting 2023-07-07 15:44:44 -07:00
Tuukka Ojala 29a06511a9 Fix accessibility issues in modal component
* Fix modal aria role
* Trap focusing with tab / shift+tab inside the modal
* Restore keyboard focus when closing modal
* Automatically move keyboard focus to first focusable element unless specified otherwise
* Keyboard shortcut help modal: move keyboard focus to modal title
* Keyboard shortcut help modal: change close control from link to button
2023-07-07 15:44:44 -07:00
Jean Khawand bfb4fc1c36 Add Notion integration 2023-07-07 15:20:14 -07:00
dependabot[bot] 06c37a132f Bump golang.org/x/oauth2 from 0.9.0 to 0.10.0
Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.9.0 to 0.10.0.
- [Commits](https://github.com/golang/oauth2/compare/v0.9.0...v0.10.0)

---
updated-dependencies:
- dependency-name: golang.org/x/oauth2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-05 19:52:15 -07:00
mrtnvgr 70b3061946 fix(css): improve responsive design 2023-06-30 17:37:51 -07:00
xl 356d32c6fe Add user setting for marking entry as read on view 2023-06-29 21:03:05 -07:00
mrtnvgr 6046a74a64 feat: improve russian translation 2023-06-29 20:54:29 -07:00
dependabot[bot] 56fbea4bd3 Bump github.com/mccutchen/go-httpbin/v2 from 2.9.1 to 2.9.2
Bumps [github.com/mccutchen/go-httpbin/v2](https://github.com/mccutchen/go-httpbin) from 2.9.1 to 2.9.2.
- [Release notes](https://github.com/mccutchen/go-httpbin/releases)
- [Commits](https://github.com/mccutchen/go-httpbin/compare/v2.9.1...v2.9.2)

---
updated-dependencies:
- dependency-name: github.com/mccutchen/go-httpbin/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-27 20:49:37 -07:00
Wayne Tan ee0dcdf753 Bump go-oidc to v3.6.0 2023-06-27 20:21:51 -07:00
Frédéric Guillot 5550d662a2 Add the possibility to run cleanup tasks from the command line 2023-06-25 11:41:30 -07:00
Frédéric Guillot 3dc8e5ebaf Refresh feeds in the cronjob in parallel 2023-06-25 10:35:59 -07:00
Frédéric Guillot c85b19098d Add the possibility to run Miniflux as a cronjob 2023-06-24 22:29:30 -07:00
kramanathan01 c3250257b1 Use go-httpbin to run tests locally and avoid remote calls to httpbin.org
https://github.com/mccutchen/go-httpbin is MIT licensed and implements httpbin interfaces in Golang. 

Combining this package with `httptest.Server` allows client unit tests to run entirely locally with no dependency on remote calls to httpbin.org
2023-06-24 22:05:47 -07:00
privatmamtora fffa74f782 Display tags when viewing entries 2023-06-24 17:44:37 -07:00
kramanathan01 fa3de272e8 GET categories returns total_unread & feed_count 2023-06-24 17:04:27 -07:00
Frédéric Guillot b13c7e328a Improve date parser to handle various broken date formats 2023-06-24 15:27:33 -07:00
Frédéric Guillot 30d4b8986a Avoid "pq: time zone displacement out of range" errors 2023-06-24 15:09:58 -07:00
Frédéric Guillot aadbd5adf3 Improve entry existance check to make better use of index 2023-06-24 13:21:07 -07:00
Frédéric Guillot b552c293ca Add unique index enclosures_user_entry_url_idx 2023-06-24 11:59:58 -07:00
Frédéric Guillot a2f15b3c36 Add translation key: form.integration.linkding_bookmark 2023-06-24 10:38:07 -07:00
movd 736fb7320e Add mark as unread for Linkding integration 2023-06-24 10:38:07 -07:00
Gabriel Augendre 765b4c6424 Add sub-folder support for Wallabag integration 2023-06-24 10:14:46 -07:00
Frédéric Guillot df472254d3 Use RockyLinux to build RPM package 2023-06-23 20:56:53 -07:00
Frédéric Guillot 98167487aa Remove test dependency on httpbin.org
httpbin.org is very flaky
2023-06-23 17:52:55 -07:00
Frédéric Guillot 257ef7e573 Disable CGO when building RPM package 2023-06-22 21:22:44 -07:00
Frédéric Guillot 30288fec8d Disable CGO when building Docker images 2023-06-22 21:19:44 -07:00
Frédéric Guillot e234b86af6 Update ChangeLog 2023-06-21 20:42:31 -07:00
dependabot[bot] d00803617e Bump github.com/tdewolff/minify/v2 from 2.12.6 to 2.12.7
Bumps [github.com/tdewolff/minify/v2](https://github.com/tdewolff/minify) from 2.12.6 to 2.12.7.
- [Release notes](https://github.com/tdewolff/minify/releases)
- [Commits](https://github.com/tdewolff/minify/compare/v2.12.6...v2.12.7)

---
updated-dependencies:
- dependency-name: github.com/tdewolff/minify/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-19 15:57:40 -07:00
fred af74e39fa7 Add test case to parse Atom icon URL 2023-06-19 15:17:41 -07:00
fred 8646d61182 Replace copyright header with SPDX identifier 2023-06-19 15:00:45 -07:00
fred 28775f5e10 Refactor entry/feed query builder sorting to match SQL semantic 2023-06-19 14:13:19 -07:00
dependabot[bot] 095bec072c Bump github.com/prometheus/client_golang from 1.15.1 to 1.16.0
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.15.1 to 1.16.0.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.15.1...v1.16.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-15 21:38:10 -07:00
dependabot[bot] bd0f21e139 Bump golang.org/x/oauth2 from 0.8.0 to 0.9.0
Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.8.0 to 0.9.0.
- [Commits](https://github.com/golang/oauth2/compare/v0.8.0...v0.9.0)

---
updated-dependencies:
- dependency-name: golang.org/x/oauth2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-13 19:43:21 -07:00
dependabot[bot] 69414dcd7c Bump golang.org/x/term from 0.8.0 to 0.9.0
Bumps [golang.org/x/term](https://github.com/golang/term) from 0.8.0 to 0.9.0.
- [Commits](https://github.com/golang/term/compare/v0.8.0...v0.9.0)

---
updated-dependencies:
- dependency-name: golang.org/x/term
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-12 17:46:32 -07:00
Kristof Mattei 28ee9cad19 fix: remove title for a hrefs 2023-06-05 20:09:43 -07:00
Naïm Favier 7d1609bd93 Order history by changed_at, published_at
When a bunch of entries are marked as read at once, they should have the
same `changed_at`; fall back to sorting them chronologically by
publication date.
2023-06-04 15:03:57 -07:00
Ryan Stafford 1aeb1b20da Use image included in feed as feed icon 2023-06-04 15:01:59 -07:00
Ztec 228bb62df4 Add Media Player and resume to last playback position
In order to ease podcast listening, the player can be put on top of the feed entry as main content.
Use the `Use podcast player` option to enable that. It works on audio and video.

Also, when playing audio or video, progression will be saved in order to be able to resume listening later.
This position saving is done using the original attachement/enclosures player AND podcast player and do not rely on
the podcast player option ti be enabled.

Additionally, I made the player fill the width with the entry container to ease seeking and have a bigger video.

updateEnclosures now keep existing enclosures based on URL

When feeds get updated, enclosures entries are always wiped and re-created. This cause two issue
 - enclosure progression get lost in the process
 - enclosure ID changes

I used the URL as identifier of an enclosure. Not perfect but hopefully should work.
When an enclosure already exist, I simply do nothing and leave the entry as is in the database.
If anyone is listening/watching to this enclosure during the refresh, the id stay coherent and progression saving still works.

The updateEnclosures function got a bit more complex. I tried to make it the more clear I could.
Some optimisation are possible but would make the function harder to read in my opinion.

I'm not sure if this is often the case, but some feeds may include tracking or simply change the url each
time we update the feed. In those situation, enclosures ids and progression will be lost.

I have no idea how to handle this last situation. Use the size instead/alongside url to define the identity of an enclosure ?

Translation: english as placeholder for every language except French

Aside, I tested a video feed and fixed a few things for it. In fact, the MimeType was not working
at all on my side, and found a pretty old stackoverflow discussion that suggest to use an Apple non-standard MimeType for
m4v video format. I only did one substitution because I only have one feed to test. Any new video feed can make this go away
or evolve depending on the situation. Real video feeds does not tend to be easy to find and test extensively this.

Co-authored-by: toastal
2023-06-04 14:49:46 -07:00
Ryan Cao c4e2eaa609 Add default tag names for Linkding integration 2023-05-30 21:02:27 -07:00
Romain de Laage 118e18190d Mark only globally visible entries when marking all entries from UI 2023-05-30 20:29:44 -07:00
Jonatas Baldin 31c4172540 Remove the "í" letter from the portuguese "lido" word 2023-05-28 19:13:36 -07:00
dependabot[bot] 93b43d37df Bump github.com/tdewolff/minify/v2 from 2.12.5 to 2.12.6
Bumps [github.com/tdewolff/minify/v2](https://github.com/tdewolff/minify) from 2.12.5 to 2.12.6.
- [Release notes](https://github.com/tdewolff/minify/releases)
- [Commits](https://github.com/tdewolff/minify/compare/v2.12.5...v2.12.6)

---
updated-dependencies:
- dependency-name: github.com/tdewolff/minify/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-26 16:13:54 -07:00
Frédéric Guillot 3987a2ce8a Reading time is not aligned correctly with the latest Safari
Fixes #1873
2023-05-10 20:38:18 -07:00
Frédéric Guillot fe039b3c55 Use glyphs of the same size on keyboard shortcuts page 2023-05-10 20:09:13 -07:00
dependabot[bot] 7537932154 Bump golang.org/x/oauth2 from 0.7.0 to 0.8.0
Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.7.0 to 0.8.0.
- [Commits](https://github.com/golang/oauth2/compare/v0.7.0...v0.8.0)

---
updated-dependencies:
- dependency-name: golang.org/x/oauth2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-09 19:21:59 -07:00
dependabot[bot] 902f6cb9c0 Bump golang.org/x/crypto from 0.8.0 to 0.9.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.8.0 to 0.9.0.
- [Commits](https://github.com/golang/crypto/compare/v0.8.0...v0.9.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-09 19:15:13 -07:00
Frédéric Guillot 790ce5be6d Increase golangci-lint timeout value 2023-05-09 19:06:36 -07:00
dependabot[bot] bcfc7a883c Bump golang.org/x/net from 0.9.0 to 0.10.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.9.0 to 0.10.0.
- [Commits](https://github.com/golang/net/compare/v0.9.0...v0.10.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-08 17:14:56 -07:00
Pontus Jensen Karlsson 9fdbd180df Added maskable versions of the PWA icon.
Recent versions of Android allows the user to choose their own
homescreen icons shape. This introduces the concept of maskable PWA
icons, which without the "purpose" tag and properly padded icons makes
the homescreen icon look really boxy and weird.

This adds a new version of the icon with more padding in three sizes, as
well as the "purpose" attribute in the manifest.json file. The three old
icons are retained for compatibility with desktop and iOS.
2023-05-08 16:35:37 -07:00
Frédéric Guillot 4c0c658152 Update ChangeLog 2023-05-06 14:09:45 -07:00
dependabot[bot] 88062ab9f9 Bump golang.org/x/term from 0.7.0 to 0.8.0
Bumps [golang.org/x/term](https://github.com/golang/term) from 0.7.0 to 0.8.0.
- [Commits](https://github.com/golang/term/compare/v0.7.0...v0.8.0)

---
updated-dependencies:
- dependency-name: golang.org/x/term
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-04 17:04:42 -07:00
Adriano Di Luzio 85856baf13 fix: Point to docs for URL rewrite rules too 2023-05-04 17:04:21 -07:00
dependabot[bot] 2d33b7df6e Bump github.com/prometheus/client_golang from 1.15.0 to 1.15.1
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.15.0 to 1.15.1.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.15.0...v1.15.1)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-03 17:58:32 -07:00
Davide Masserut 5d8a8878d5 Update scraping rules for ilpost.it 2023-05-02 17:07:25 -07:00
dependabot[bot] 8d2dab44d8 Bump github.com/lib/pq from 1.10.8 to 1.10.9
Bumps [github.com/lib/pq](https://github.com/lib/pq) from 1.10.8 to 1.10.9.
- [Release notes](https://github.com/lib/pq/releases)
- [Commits](https://github.com/lib/pq/compare/v1.10.8...v1.10.9)

---
updated-dependencies:
- dependency-name: github.com/lib/pq
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-02 16:19:33 -07:00
dependabot[bot] d435e67a36 Bump mvdan.cc/xurls/v2 from 2.4.0 to 2.5.0
Bumps [mvdan.cc/xurls/v2](https://github.com/mvdan/xurls) from 2.4.0 to 2.5.0.
- [Release notes](https://github.com/mvdan/xurls/releases)
- [Commits](https://github.com/mvdan/xurls/compare/v2.4.0...v2.5.0)

---
updated-dependencies:
- dependency-name: mvdan.cc/xurls/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-17 16:58:42 -07:00
Romain de Laage 33c4b5188c Add a rewrite rule to remove clickbait titles 2023-04-15 18:25:43 -07:00
dependabot[bot] 8161085714 Bump github.com/lib/pq from 1.10.7 to 1.10.8
Bumps [github.com/lib/pq](https://github.com/lib/pq) from 1.10.7 to 1.10.8.
- [Release notes](https://github.com/lib/pq/releases)
- [Commits](https://github.com/lib/pq/compare/v1.10.7...v1.10.8)

---
updated-dependencies:
- dependency-name: github.com/lib/pq
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-14 19:13:51 -07:00
dependabot[bot] 6493239484 Bump github.com/prometheus/client_golang from 1.14.0 to 1.15.0
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.14.0 to 1.15.0.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.14.0...v1.15.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-13 20:48:57 -07:00
dependabot[bot] a143681af3 Bump golang.org/x/crypto from 0.7.0 to 0.8.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.7.0 to 0.8.0.
- [Release notes](https://github.com/golang/crypto/releases)
- [Commits](https://github.com/golang/crypto/compare/v0.7.0...v0.8.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-07 16:12:41 -07:00
Emiel Wiedijk 5a88e0465e Update rewrite rules for theverge.com
Articles on The Verge sometimes contain a section for related articles.
This section can be distracting in reader mode. Therefore, filter the
related article section using the scraper rules.
2023-04-07 16:12:19 -07:00
dependabot[bot] 30bb901d7c Bump golang.org/x/oauth2 from 0.6.0 to 0.7.0
Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.6.0 to 0.7.0.
- [Release notes](https://github.com/golang/oauth2/releases)
- [Commits](https://github.com/golang/oauth2/compare/v0.6.0...v0.7.0)

---
updated-dependencies:
- dependency-name: golang.org/x/oauth2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-07 16:02:42 -07:00
dependabot[bot] 40418fcf6f Bump golang.org/x/net from 0.8.0 to 0.9.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.8.0 to 0.9.0.
- [Release notes](https://github.com/golang/net/releases)
- [Commits](https://github.com/golang/net/compare/v0.8.0...v0.9.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-06 17:42:43 -07:00
dependabot[bot] ad85e5be80 Bump golang.org/x/term from 0.6.0 to 0.7.0
Bumps [golang.org/x/term](https://github.com/golang/term) from 0.6.0 to 0.7.0.
- [Release notes](https://github.com/golang/term/releases)
- [Commits](https://github.com/golang/term/compare/v0.6.0...v0.7.0)

---
updated-dependencies:
- dependency-name: golang.org/x/term
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-05 20:06:59 -07:00
Frédéric Guillot aa9b18a8d6 Make sure PROXY_IMAGES option is backward compatible
Bug introduced in PR #1610

Fixes #1753
2023-04-02 18:35:43 -07:00
Jake Walker 8b6dd3e599 Keep other table rows and columns 2023-04-02 17:50:19 -07:00
Jake Walker 49d2596fc6 Basic table removal rule 2023-04-02 17:50:19 -07:00
rook1e 9a826bbe6f feat: support searching well-known urls in subdirectory 2023-04-02 17:44:14 -07:00
rook1e acc9186a59 fix: extra-long title overflow 2023-04-02 17:37:25 -07:00
dzaikos 7d252ea45b Add swipe as option for gesture navigation between entries.
* Refactor `TouchHandler` to handle double-tap and swipe gestures.
  * Renamed existing `onTouch` JavaScript methods to `onItemTouch` and
    added `onContentTouch` methods for swipe gesture.
  * Refactor double-tap. It's now a method in `TouchHandler` versus
    anonymous functions in `listen()` method.
* Updated CSS classes.
  * Added `touch-action` CSS for `.entry-content`.
  * Renamed CSS classes for adding events in `TouchHandler`.
* Updated users settings to replace checkbox for double tap with select
  for none, double tap, or swipe.
* Added database migrations for new gesture_nav option.
  * Rename `users.double_tap` to `users.gesture_nav` and migrate
    existing user settings.
* Updated translation files. (Non-English updated with Google
  Translate.)

Resolves #1449, closes #1495
2023-03-28 18:00:57 -07:00
Frédéric Guillot 140a40acaf Use secrets.GITHUB_TOKEN to push images instead of a PAT 2023-03-27 21:29:33 -07:00
toastal 56efba66f5 Prefer typographic punctuation
For a long time, we’ve not been limited to ASCII and have machines that
can properly render the typographically-correct punctuation symbols for
our languages. This leads to a better, clearer reading experience and
also matches the `<meta charset="utf-8">` and the the use of such
punctuation on FAQs.

Changes:
• Ellipsis: `...` → `…` (https://en.wikipedia.org/wiki/Ellipsis)
• Apostrophe: `'` → `’` (https://en.wikipedia.org/wiki/Apostrophe)

While I could try to do research on other languages, I’m not a native
speaker in them and wouldn’t feel comfortable making any adjustments
outside of English.
2023-03-27 20:55:25 -07:00
Frédéric Guillot 7e612cddd3 Update issue templates 2023-03-26 19:13:53 -07:00
Davide Masserut 034e46700c Process older entries first
Feed entries are usually ordered from most to least recent.

Processing older entries first ensures that their creation timestamp
is lower than that of newer entries.

This is useful when we order by creation, because then we get a
consistent timeline.
2023-03-25 16:19:07 -07:00
Daniel Jakots ac8f64d7a1 Set Prometheus as datasource everywhere
Requested by @lnicola.
2023-03-24 20:12:13 -07:00
Daniel Jakots b536e05fee Fix grafana dashboard 2023-03-24 20:12:13 -07:00
dependabot[bot] 6eed037186 Bump actions/setup-go from 3 to 4
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 3 to 4.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-20 20:20:59 -07:00
Frédéric Guillot 5912400dee Push Docker images to Quay.io (RedHat) 2023-03-19 21:25:05 -07:00
Frédéric Guillot ab209df78f Update ChangeLog 2023-03-16 19:34:20 -07:00
dependabot[bot] 11a352dcfd Bump github.com/tdewolff/minify/v2 from 2.12.4 to 2.12.5
Bumps [github.com/tdewolff/minify/v2](https://github.com/tdewolff/minify) from 2.12.4 to 2.12.5.
- [Release notes](https://github.com/tdewolff/minify/releases)
- [Commits](https://github.com/tdewolff/minify/compare/v2.12.4...v2.12.5)

---
updated-dependencies:
- dependency-name: github.com/tdewolff/minify/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-16 18:04:23 -07:00
Frédéric Guillot 9ae6922bdc Fix null reference in toggle entry attachments shortcut
Fixes #1723
2023-03-13 20:20:35 -07:00
Frédéric Guillot ea8c3c801a Update Security policy 2023-03-13 19:56:47 -07:00
Frédéric Guillot eb9508502c Avoid XSS when opening a broken image due to unescaped ServerError in proxy handler
Creating an RSS feed item with the inline description containing an `<img>` tag
with a `srcset` attribute pointing to an invalid URL like
`http:a<script>alert(1)</script>`, we can coerce the proxy handler into an error
condition where the invalid URL is returned unescaped and in full.

This results in JavaScript execution on the Miniflux instance as soon as the
user is convinced to open the broken image.
2023-03-12 22:36:03 -07:00
Frédéric Guillot b46b5dfb2a Use r.RemoteAddr to check /metrics endpoint network access
HTTP headers like X-Forwarded-For or X-Real-Ip can be easily spoofed. As
such, it cannot be used to test if the client IP is allowed.

The recommendation is to use HTTP Basic authentication to protect the
metrics endpoint, or run Miniflux behind a trusted reverse-proxy.
2023-03-11 20:53:12 -08:00
Frédéric Guillot 877dbed5e8 Add HTTP Basic authentication for /metrics endpoint 2023-03-11 20:13:52 -08:00
fructurj 79ff381c4c Update es_ES.json 2023-03-11 17:38:07 -08:00
dependabot[bot] f6a672738a Bump golang.org/x/crypto from 0.6.0 to 0.7.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.6.0 to 0.7.0.
- [Release notes](https://github.com/golang/crypto/releases)
- [Commits](https://github.com/golang/crypto/compare/v0.6.0...v0.7.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-06 20:38:55 -08:00
dependabot[bot] e4964d6933 Bump golang.org/x/oauth2 from 0.5.0 to 0.6.0
Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.5.0 to 0.6.0.
- [Release notes](https://github.com/golang/oauth2/releases)
- [Commits](https://github.com/golang/oauth2/compare/v0.5.0...v0.6.0)

---
updated-dependencies:
- dependency-name: golang.org/x/oauth2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-06 20:27:58 -08:00
Davide Masserut 755c9af47d Update scraping rules for ilpost.it 2023-03-01 20:04:25 -08:00
Frédéric Guillot 02e4b8eadc Update GitHub Actions to use Go 1.20 2023-03-01 19:56:06 -08:00
Frédéric Guillot aaa1625724 Ignore empty link when discovering feeds 2023-02-26 17:19:26 -08:00
Frédéric Guillot bb5f3ec6a8 Disable CGO explicitly to make sure the binary is statically linked
Apparently this behavior has been changed in Go 1.20: https://tip.golang.org/doc/go1.20#cgo
2023-02-25 16:55:11 -08:00
Sigsign 8804eb9a78 Update Japanese translation 2023-02-25 15:58:39 -08:00
Romain de Laage 2c2700a31d Proxy support for several media types
closes #615
closes #635
2023-02-25 15:57:59 -08:00
privatmamtora 8f9ccc6540 Parse <category> from Feeds (RSS, Atom and JSON) 2023-02-24 20:52:45 -08:00
dependabot[bot] ff8d68c151 Bump github.com/PuerkitoBio/goquery from 1.8.0 to 1.8.1
Bumps [github.com/PuerkitoBio/goquery](https://github.com/PuerkitoBio/goquery) from 1.8.0 to 1.8.1.
- [Release notes](https://github.com/PuerkitoBio/goquery/releases)
- [Commits](https://github.com/PuerkitoBio/goquery/compare/v1.8.0...v1.8.1)

---
updated-dependencies:
- dependency-name: github.com/PuerkitoBio/goquery
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-20 19:24:57 -08:00
the7thNightmare 1fb0bc29db Update the plural for Indonesian
Copied from the zh_CN plural
2023-02-19 19:53:06 -08:00
Ananta Krsna dasa a1593b8942 Run the application in one command 2023-02-19 11:56:51 -08:00
Ananta Krsna dasa 20c4cb770e Bring back the health check condition to depends_on 2023-02-19 11:56:51 -08:00
Ananta Krsna dasa db7a4ae7e9 Remove deprecated version element 2023-02-19 11:56:51 -08:00
the7thNightmare aabb766fad Add Indonesian Language 2023-02-19 11:49:17 -08:00
the7thNightmare 8dce3099d9 Add Indonesian Language 2023-02-19 11:49:17 -08:00
dependabot[bot] fb2b43176f Bump golang.org/x/net from 0.6.0 to 0.7.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.6.0 to 0.7.0.
- [Release notes](https://github.com/golang/net/releases)
- [Commits](https://github.com/golang/net/compare/v0.6.0...v0.7.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-14 19:06:58 -08:00
dependabot[bot] 2f6034c63c Bump golang.org/x/crypto from 0.5.0 to 0.6.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.5.0 to 0.6.0.
- [Release notes](https://github.com/golang/crypto/releases)
- [Commits](https://github.com/golang/crypto/compare/v0.5.0...v0.6.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-09 17:54:31 -08:00
dependabot[bot] 67190fc988 Bump golang.org/x/oauth2 from 0.4.0 to 0.5.0
Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.4.0 to 0.5.0.
- [Release notes](https://github.com/golang/oauth2/releases)
- [Commits](https://github.com/golang/oauth2/compare/v0.4.0...v0.5.0)

---
updated-dependencies:
- dependency-name: golang.org/x/oauth2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-09 17:49:00 -08:00
dependabot[bot] e4c0495646 Bump golang.org/x/net from 0.5.0 to 0.6.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.5.0 to 0.6.0.
- [Release notes](https://github.com/golang/net/releases)
- [Commits](https://github.com/golang/net/compare/v0.5.0...v0.6.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-08 20:15:36 -08:00
dependabot[bot] a7508b2746 Bump golang.org/x/term from 0.4.0 to 0.5.0
Bumps [golang.org/x/term](https://github.com/golang/term) from 0.4.0 to 0.5.0.
- [Release notes](https://github.com/golang/term/releases)
- [Commits](https://github.com/golang/term/compare/v0.4.0...v0.5.0)

---
updated-dependencies:
- dependency-name: golang.org/x/term
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-07 20:16:21 -08:00
Wojtek 34408b50a7 Add CSS classes to differentiate between category/feed/entry view and icons 2023-02-06 20:46:42 -08:00
Marie Ramlow 48acd1feca Add rewrite and scraper rules for blog.cloudflare.com 2023-02-05 21:01:42 -08:00
Ryan Cao 8d51fd8ff5 fix: add color-scheme to themes 2023-02-05 20:58:23 -08:00
Martin Vietz a44ba4abcb Add toggle open/close entry attachments shortcut 2023-02-05 20:51:51 -08:00
dependabot[bot] b338c9b3c2 Bump github.com/yuin/goldmark from 1.5.3 to 1.5.4
Bumps [github.com/yuin/goldmark](https://github.com/yuin/goldmark) from 1.5.3 to 1.5.4.
- [Release notes](https://github.com/yuin/goldmark/releases)
- [Commits](https://github.com/yuin/goldmark/compare/v1.5.3...v1.5.4)

---
updated-dependencies:
- dependency-name: github.com/yuin/goldmark
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-02 20:07:07 -08:00
xdavidwu 08f7835f5d sanitizer: allow id in <sup>
One of blogs I read uses anchor on <sup> to link a footnote back to its
reference.
2023-01-31 17:53:45 -08:00
dependabot[bot] d38fc80bad Bump docker/build-push-action from 3 to 4
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 3 to 4.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-30 17:04:35 -08:00
Frédéric Guillot b2fd84e0d3 Update ChangeLog 2023-01-29 17:01:14 -08:00
Sigsign e64f488654 Update Japanese translations 2023-01-28 17:58:56 -08:00
Sigsign 8017ed2cf6 Sort like en_US.json 2023-01-28 17:58:56 -08:00
Davide Masserut 65febebd40 Fix header items wrapping 2023-01-17 20:00:13 -08:00
Frédéric Guillot 2e047dff98 Add option to enable or disable double tap 2023-01-14 16:59:52 -08:00
Frédéric Guillot 6612e42668 Improve PWA display mode label in settings page 2023-01-14 15:39:09 -08:00
dependabot[bot] 2956bbad8d Bump golang.org/x/oauth2 from 0.3.0 to 0.4.0
Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.3.0 to 0.4.0.
- [Release notes](https://github.com/golang/oauth2/releases)
- [Commits](https://github.com/golang/oauth2/compare/v0.3.0...v0.4.0)

---
updated-dependencies:
- dependency-name: golang.org/x/oauth2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-05 07:23:59 -08:00
dependabot[bot] 3285a00ebc Bump golang.org/x/crypto from 0.4.0 to 0.5.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.4.0 to 0.5.0.
- [Release notes](https://github.com/golang/crypto/releases)
- [Commits](https://github.com/golang/crypto/compare/v0.4.0...v0.5.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-05 07:23:41 -08:00
dependabot[bot] c0c8e47344 Bump golang.org/x/net from 0.4.0 to 0.5.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.4.0 to 0.5.0.
- [Release notes](https://github.com/golang/net/releases)
- [Commits](https://github.com/golang/net/compare/v0.4.0...v0.5.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-05 07:14:53 -08:00
dependabot[bot] 3fc02df70f Bump golang.org/x/term from 0.3.0 to 0.4.0
Bumps [golang.org/x/term](https://github.com/golang/term) from 0.3.0 to 0.4.0.
- [Release notes](https://github.com/golang/term/releases)
- [Commits](https://github.com/golang/term/compare/v0.3.0...v0.4.0)

---
updated-dependencies:
- dependency-name: golang.org/x/term
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-05 07:06:56 -08:00
Tadeusz Magura-Witkowski c071201e37 Update pl_PL.json
Fixed message for form.feed.label.disable (for some reason this was in Russian?).
2022-12-29 12:56:50 -08:00
Davide Masserut 690d66ce0b Update scraping rules for ilpost.it 2022-12-27 13:33:41 -08:00
Davide Masserut ef312ef770 Update scraping rule for ilpost.it 2022-12-16 15:07:10 -08:00
Davide Masserut c0bed53b42 Add scraping rule for ilpost.it 2022-12-15 19:53:12 -08:00
Davide Masserut c0ee3ed375 Update reading time HTML element after fetching the original web page 2022-12-14 19:53:04 -08:00
Davide Masserut ce35b46fee Add category feeds refresh 2022-12-12 19:41:30 -08:00
Frédéric Guillot e12c263fc9 Update Changelog 2022-12-10 10:45:34 -08:00
dependabot[bot] 281c9be6c8 Bump golang.org/x/crypto from 0.3.0 to 0.4.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.3.0 to 0.4.0.
- [Release notes](https://github.com/golang/crypto/releases)
- [Commits](https://github.com/golang/crypto/compare/v0.3.0...v0.4.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-07 20:28:01 -08:00
dependabot[bot] b92debf9c9 Bump golang.org/x/net from 0.3.0 to 0.4.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.3.0 to 0.4.0.
- [Release notes](https://github.com/golang/net/releases)
- [Commits](https://github.com/golang/net/compare/v0.3.0...v0.4.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-07 20:16:18 -08:00
nyanpasu64 b6c368c39c Disable double-tap mobile gesture if swipe gesture is disabled
Fixes #441.
2022-12-06 20:34:15 -08:00
dependabot[bot] de92e3e472 Bump golang.org/x/oauth2 from 0.2.0 to 0.3.0
Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.2.0 to 0.3.0.
- [Release notes](https://github.com/golang/oauth2/releases)
- [Commits](https://github.com/golang/oauth2/compare/v0.2.0...v0.3.0)

---
updated-dependencies:
- dependency-name: golang.org/x/oauth2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-06 19:57:18 -08:00
Harry Cheng d9777f1439 Skip integrations if there are no entries to push 2022-12-04 12:58:10 -08:00
mutantmonkey b4643fd27f Enable TLS-ALPN-01 challenge for ACME
This type of challenge works purely at the TLS layer and is compatible
with SNI proxies. The existing HTTP-01 challenge support has been left
as-is.

Fixes #1476.
2022-11-16 20:41:55 -08:00
Frédéric Guillot d9cf3f9c38 Preconfigure Miniflux for GitHub Codespaces 2022-11-17 03:49:05 +00:00
Frédéric Guillot dfd6b769b9 Create devcontainer.json 2022-11-16 17:34:55 -08:00
dependabot[bot] 68780de6fc Bump golang.org/x/crypto from 0.2.0 to 0.3.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.2.0 to 0.3.0.
- [Release notes](https://github.com/golang/crypto/releases)
- [Commits](https://github.com/golang/crypto/compare/v0.2.0...v0.3.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-16 16:18:50 -08:00
Frédéric Guillot 93715b542c Revert "scraper follow the only link"
This reverts commit 10207967c4.
2022-11-14 17:45:40 -08:00
Frédéric Guillot de1a06e3e8 Add missing check in followTheOnlyLink() that leads to a panic
Bug introduced in PR #1290. Fixes #1631.
2022-11-14 16:44:02 -08:00
Frédéric Guillot bfebf946c2 Update ChangeLog 2022-11-13 15:22:25 -08:00
Frédéric Guillot 6094130f61 Update Go dependencies 2022-11-13 14:56:43 -08:00
Frédéric Guillot d1bd0073cc Pin Postgres image version in docker-compose examples to avoid unexpected upgrades 2022-11-13 14:14:04 -08:00
Juan Pedro Bretti Mandarano 789e30fdff Locale terms normalization 2 2022-11-13 13:55:08 -08:00
Juan Pedro Bretti Mandarano 04507a8a34 Locale terms normalization #1619 2022-11-13 13:55:08 -08:00
Frédéric Guillot 1ded3f8bc7 Update integration tests 2022-11-12 21:03:43 -08:00
Frédéric Guillot 3d64162f06 Allow Content-Type and Accept headers to CORS policy 2022-11-12 21:03:43 -08:00
George Angelopoulos 79357a527f Use $(...) notation instead of legacy backticked ...
This is based on a shellcheck recommendation.
https://www.shellcheck.net/wiki/SC2006
2022-11-12 20:30:44 -08:00
George Angelopoulos 1e16e19d11 use dirs file for debian package
Instead of running mkdir from debian/rules, the native way to create the
necessary directories is with the dirs file which is read by the
dh_installdirs helper script.

See:
* https://www.debian.org/doc/manuals/maint-guide/dother.en.html#dirs
* dh_installdirs(1) manual page

I am not aware of any specific problems that could arise from doing it
manually instead of using dh_installdirs. But sticking to the native
approach might be a good idea.
2022-11-12 20:30:44 -08:00
Romain de Laage efa8bfcf0e Use custom home page in PWA 2022-11-12 20:12:39 -08:00
dependabot[bot] 1351761f81 Bump golang.org/x/term from 0.1.0 to 0.2.0
Bumps [golang.org/x/term](https://github.com/golang/term) from 0.1.0 to 0.2.0.
- [Release notes](https://github.com/golang/term/releases)
- [Commits](https://github.com/golang/term/compare/v0.1.0...v0.2.0)

---
updated-dependencies:
- dependency-name: golang.org/x/term
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-07 20:35:16 -08:00
dependabot[bot] 962a0460cc Bump github.com/prometheus/client_golang from 1.13.0 to 1.13.1
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.13.0 to 1.13.1.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/v1.13.1/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.13.0...v1.13.1)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-07 19:49:37 -08:00
jebbs 10207967c4 scraper follow the only link
* in some cases, what the scraper got is only a landing page, user can use scraper rules to extract the link of the landing page and follow it
* it also fix the  wrong scrape rule apply when the server redirects it to another host
2022-10-31 19:49:34 -07:00
Frédéric Guillot 242eeaf07e Update golang.org/x/* dependencies 2022-10-27 18:09:19 -07:00
Romain de Laage 550e7d0415 Add matrix bot support 2022-10-27 17:53:19 -07:00
Romain de Laage 3f14d08095 Proxify images in API responses 2022-10-27 17:33:18 -07:00
Frédéric Guillot 206be5ba15 Rename column to CategoriesSortingOrder 2022-10-25 20:06:28 -07:00
Romain de Laage 83e1f154b5 Add optional sort option in category page
closes #1552
2022-10-25 20:06:28 -07:00
Romain de Laage ec47106c26 Remove dependency to go-server-timing
fix #1586
2022-10-23 16:59:05 -07:00
Dave Marquard 74b69a4c7c Add support for the continuation parameter and result for Google Reader API ID calls
Support the ``continuation parameter and result for Google Reader API ID calls. Allows clients to support paging of results / fetching additional results when the number of entries exceed the limit parameter passed in by the client.
2022-10-23 16:49:45 -07:00
George Angelopoulos 84d5a9a354 Use automatic variable for build target file names 2022-10-19 20:37:28 -07:00
Romain de Laage eb86773039 Recalbox rewrite rule 2022-10-19 20:13:44 -07:00
Michael van Tricht 44ca5b8591 Fix reading time dutch text 2022-10-17 21:16:41 -07:00
Frédéric Guillot 95e125dfc7 Update ChangeLog 2022-10-16 14:29:17 -07:00
jgbresson 7f6ce16d85 Add scraping rules for theverge.com 2022-10-16 11:58:35 -07:00
jgbresson aa47789f55 Add add_dynamic_image rewrite rule for theverge.com 2022-10-16 11:57:01 -07:00
Dave Marquard 7a961babd4 support date filtering for all google reader api item ID calls 2022-10-16 11:43:34 -07:00
Frédéric Guillot d947b0194b Handle RSS entries with only a GUID permalink 2022-10-09 16:58:25 -07:00
jtagcat cd7f01f573 client.New(): accept endpoint URLs with /v1/ 2022-10-03 19:49:45 -07:00
dependabot[bot] 159abf7b7d Bump github.com/tdewolff/minify/v2 from 2.12.2 to 2.12.4
Bumps [github.com/tdewolff/minify/v2](https://github.com/tdewolff/minify) from 2.12.2 to 2.12.4.
- [Release notes](https://github.com/tdewolff/minify/releases)
- [Commits](https://github.com/tdewolff/minify/compare/v2.12.2...v2.12.4)

---
updated-dependencies:
- dependency-name: github.com/tdewolff/minify/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-03 17:41:04 -07:00
dependabot[bot] 1b6eafa7d9 Bump github.com/yuin/goldmark from 1.4.15 to 1.5.2
Bumps [github.com/yuin/goldmark](https://github.com/yuin/goldmark) from 1.4.15 to 1.5.2.
- [Release notes](https://github.com/yuin/goldmark/releases)
- [Commits](https://github.com/yuin/goldmark/compare/v1.4.15...v1.5.2)

---
updated-dependencies:
- dependency-name: github.com/yuin/goldmark
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-26 16:12:44 -07:00
dependabot[bot] 42928e0a9d Bump github.com/tdewolff/minify/v2 from 2.12.1 to 2.12.2
Bumps [github.com/tdewolff/minify/v2](https://github.com/tdewolff/minify) from 2.12.1 to 2.12.2.
- [Release notes](https://github.com/tdewolff/minify/releases)
- [Commits](https://github.com/tdewolff/minify/compare/v2.12.1...v2.12.2)

---
updated-dependencies:
- dependency-name: github.com/tdewolff/minify/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-26 16:12:16 -07:00
Tomas Peterka 70c58bd346 API: Allow Basic authorization header 2022-09-19 20:56:27 -07:00
dependabot[bot] 556d88c96d Bump github.com/yuin/goldmark from 1.4.14 to 1.4.15
Bumps [github.com/yuin/goldmark](https://github.com/yuin/goldmark) from 1.4.14 to 1.4.15.
- [Release notes](https://github.com/yuin/goldmark/releases)
- [Commits](https://github.com/yuin/goldmark/compare/v1.4.14...v1.4.15)

---
updated-dependencies:
- dependency-name: github.com/yuin/goldmark
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-19 19:29:05 -07:00
Frédéric Guillot e0aa9459c9 Remove Scorecards GitHub Action 2022-09-18 17:40:17 -07:00
Frédéric Guillot e8fe4ed881 Log feed URL when submitting a subscription that returns an error 2022-09-18 17:37:53 -07:00
Frédéric Guillot 98c166c950 Update "make run" command to execute migrations 2022-09-18 16:57:40 -07:00
jtagcat 3f64e4b943 Add option to send only the URL to Wallabag 2022-09-18 16:52:28 -07:00
ericgaspar 133a1f83e3 Fix typo 2022-09-18 10:49:49 -07:00
dependabot[bot] c50a7d9938 Bump ossf/scorecard-action from 1.1.2 to 2.0.3
Bumps [ossf/scorecard-action](https://github.com/ossf/scorecard-action) from 1.1.2 to 2.0.3.
- [Release notes](https://github.com/ossf/scorecard-action/releases)
- [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md)
- [Commits](https://github.com/ossf/scorecard-action/compare/ce330fde6b1a5c9c75b417e7efc510b822a35564...865b4092859256271290c77adbd10a43f4779972)

---
updated-dependencies:
- dependency-name: ossf/scorecard-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-12 19:21:35 -07:00
dependabot[bot] 753940e0cf Bump github.com/lib/pq from 1.10.6 to 1.10.7
Bumps [github.com/lib/pq](https://github.com/lib/pq) from 1.10.6 to 1.10.7.
- [Release notes](https://github.com/lib/pq/releases)
- [Commits](https://github.com/lib/pq/compare/v1.10.6...v1.10.7)

---
updated-dependencies:
- dependency-name: github.com/lib/pq
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-12 19:21:11 -07:00
Frédéric Guillot 138fd926ee Do not convert anchors to absolute links 2022-09-11 22:40:52 -07:00
dependabot[bot] 183cb491b3 Bump github.com/yuin/goldmark from 1.4.13 to 1.4.14
Bumps [github.com/yuin/goldmark](https://github.com/yuin/goldmark) from 1.4.13 to 1.4.14.
- [Release notes](https://github.com/yuin/goldmark/releases)
- [Commits](https://github.com/yuin/goldmark/compare/v1.4.13...v1.4.14)

---
updated-dependencies:
- dependency-name: github.com/yuin/goldmark
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-05 15:36:33 -07:00
dependabot[bot] ee070de860 Bump github.com/tdewolff/minify/v2 from 2.12.0 to 2.12.1
Bumps [github.com/tdewolff/minify/v2](https://github.com/tdewolff/minify) from 2.12.0 to 2.12.1.
- [Release notes](https://github.com/tdewolff/minify/releases)
- [Commits](https://github.com/tdewolff/minify/compare/v2.12.0...v2.12.1)

---
updated-dependencies:
- dependency-name: github.com/tdewolff/minify/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-05 15:34:58 -07:00
Nicole bbc087d2ad Allow setting a custom image proxy URL 2022-08-29 20:33:47 -07:00
Frédéric Guillot b8c3153b75 Update dependencies 2022-08-28 20:50:45 -07:00
Romain de Laage d7f978da49 Allow zoom on mobile devices
See https://developer.mozilla.org/en-US/docs/Web/HTML/Viewport_meta_tag#user-scalable
2022-08-21 21:33:32 -07:00
Frédéric Guillot 0afad251e0 Fix integration tests on GitHub Actions 2022-08-21 15:31:52 -07:00
Adam B 4d847c6a74 Add scraping rule for royalroad.com
This is what I use for several stories I follow, and I thought it might be useful to other miniflux users.
2022-08-17 19:25:39 -07:00
Owen Valentine f404ddde91 Add swordscomic.com 2022-08-17 19:23:29 -07:00
Owen Valentine c8a3d953cf Add smbc-comics.com 2022-08-17 19:23:29 -07:00
Owen Valentine f851ecac78 Sort alphabetically 2022-08-17 19:23:29 -07:00
Leonid Shevtsov 1c1fcdcd3d Tweak page.categories.feed_count for UA locale 2022-08-15 20:20:23 -07:00
Leonid Shevtsov 594e9a6039 Add Ukrainian locale 2022-08-15 20:20:23 -07:00
Frédéric Guillot ffafa810da Update golang.org/x/crypto 2022-08-13 21:58:45 -07:00
Frédéric Guillot 1ca35e9364 Update ChangeLog 2022-08-13 12:15:17 -07:00
Frédéric Guillot 4dc79833da Update path to Dockerfiles in dependabot.yml 2022-08-11 21:36:28 -07:00
dependabot[bot] e8c4ce995c Bump actions/setup-go from 2 to 3
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 2 to 3.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-11 21:29:25 -07:00
dependabot[bot] 9daaffa23f Bump actions/upload-artifact from 2.3.1 to 3.1.0
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 2.3.1 to 3.1.0.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/82c141cc518b40d92cc801eee768e7aafc9c2fa2...3cea5372237819ed00197afe530f5a7ea3e805c8)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-11 21:28:20 -07:00
dependabot[bot] 63bada09e0 Bump docker/build-push-action from 2 to 3
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 2 to 3.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-11 21:27:54 -07:00
dependabot[bot] 612e86cf86 Bump docker/login-action from 1 to 2
Bumps [docker/login-action](https://github.com/docker/login-action) from 1 to 2.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v1...v2)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-11 21:26:26 -07:00
Frédéric Guillot 5abf8c6798 Rename default branch to main 2022-08-11 21:17:38 -07:00
Frédéric Guillot 992422c91f Update CodeQL workflow 2022-08-08 22:59:54 -07:00
dependabot[bot] 32ae3c4d4b Bump docker/setup-buildx-action from 1 to 2
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 1 to 2.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v1...v2)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-08 22:27:39 -07:00
dependabot[bot] 9ee9c0579f Bump golangci/golangci-lint-action from 2 to 3
Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 2 to 3.
- [Release notes](https://github.com/golangci/golangci-lint-action/releases)
- [Commits](https://github.com/golangci/golangci-lint-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: golangci/golangci-lint-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-08 22:21:03 -07:00
dependabot[bot] 39a8c8c10d Bump ossf/scorecard-action from 1.0.1 to 1.1.2
Bumps [ossf/scorecard-action](https://github.com/ossf/scorecard-action) from 1.0.1 to 1.1.2.
- [Release notes](https://github.com/ossf/scorecard-action/releases)
- [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md)
- [Commits](https://github.com/ossf/scorecard-action/compare/e3e75cf2ffbf9364bbff86cdbdf52b23176fe492...ce330fde6b1a5c9c75b417e7efc510b822a35564)

---
updated-dependencies:
- dependency-name: ossf/scorecard-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-08 22:20:29 -07:00
dependabot[bot] 49c2d3e34d Bump actions/checkout from 2 to 3
Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-08 22:19:50 -07:00
dependabot[bot] bcef6e2de4 Bump docker/setup-qemu-action from 1 to 2
Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 1 to 2.
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](https://github.com/docker/setup-qemu-action/compare/v1...v2)

---
updated-dependencies:
- dependency-name: docker/setup-qemu-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-08 22:19:02 -07:00
dependabot[bot] 26d1b8eb4c Bump github.com/prometheus/client_golang from 1.12.2 to 1.13.0
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.12.2 to 1.13.0.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.12.2...v1.13.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-08 22:17:56 -07:00
Frédéric Guillot cecab91298 Fix some linter issues 2022-08-08 22:06:38 -07:00
Frédéric Guillot 3eb3ac06b6 Revert "Google Reader API: Fix incorrect ParseInt"
This reverts commit 071e9106a8.
2022-08-03 18:16:20 -07:00
dependabot[bot] aefadfeed4 Bump github.com/yuin/goldmark from 1.1.32 to 1.4.13
Bumps [github.com/yuin/goldmark](https://github.com/yuin/goldmark) from 1.1.32 to 1.4.13.
- [Release notes](https://github.com/yuin/goldmark/releases)
- [Commits](https://github.com/yuin/goldmark/compare/v1.1.32...v1.4.13)

---
updated-dependencies:
- dependency-name: github.com/yuin/goldmark
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-01 19:33:32 -07:00
Frédéric Guillot 13fa08ad39 Handle Atom links with a text/html type defined 2022-07-31 17:43:03 -07:00
Frédéric Guillot 071e9106a8 Google Reader API: Fix incorrect ParseInt 2022-07-31 17:17:17 -07:00
Gabe Cook 405d4febd9 Parse markdown by default for blog.laravel.com 2022-07-30 20:19:09 -07:00
Gabe Cook 36df7b36ec Add parse_markdown rewrite function 2022-07-30 20:19:09 -07:00
Frédéric Guillot 9ba15e9649 Build RPM and Debian packages on GitHub Actions 2022-07-30 20:11:21 -07:00
Gabe Cook bd1dc3149e Add explosm.net scraper rule 2022-07-30 20:10:52 -07:00
Romain de Laage 03a1cfcd5e Make default home page configurable 2022-07-26 22:03:03 -07:00
Frédéric Guillot 45a9fd5af6 Revert "Don't word-wrap in article titles"
This reverts commit 15268ef4f6.

Unfortunately, it's not really usable on a mobile phone because most
titles are truncated.
2022-07-23 21:46:32 -07:00
Frédéric Guillot 224584312a Add title attribute to entry links because text could be truncated 2022-07-23 18:11:06 -07:00
Frédéric Guillot 5f29af30b0 Add missing CSS after merging PR 1506 2022-07-23 18:09:37 -07:00
ltdk 15268ef4f6 Don't word-wrap in article titles 2022-07-23 17:28:24 -07:00
Romain de Laage 3ac5095776 Highlight categories with unread entries 2022-07-23 17:18:35 -07:00
privatmamtora d7cf782019 Allow option to order by title & author 2022-07-18 21:14:00 -07:00
Frédéric Guillot 055097fdeb Add missing return statements in PR #1225 2022-07-18 21:13:21 -07:00
Ilya Brin 9805654247 Update ru_RU.json
little typos fixed
2022-07-18 20:49:01 -07:00
Gabriel Augendre 6e50ce3293 Make reading speed user-configurable 2022-07-17 19:35:24 -07:00
pawanrai9999 3a0aaddafd Added locale hi_IN
- Added translation for Hindi language used in India
- Thanks to Prince Kumar for helping in translations
                                        - जय हिन्द
2022-07-16 16:40:59 -07:00
Carsten 2659883ce5 Add rewrite rules for article URL before fetching content 2022-07-11 21:12:26 -07:00
dependabot[bot] b1f6f2e7ac Bump github.com/tdewolff/minify/v2 from 2.11.11 to 2.12.0
Bumps [github.com/tdewolff/minify/v2](https://github.com/tdewolff/minify) from 2.11.11 to 2.12.0.
- [Release notes](https://github.com/tdewolff/minify/releases)
- [Commits](https://github.com/tdewolff/minify/compare/v2.11.11...v2.12.0)

---
updated-dependencies:
- dependency-name: github.com/tdewolff/minify/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-11 20:10:43 -07:00
Alexandros Kosiaris cf96ab45c1 Support other repo owners in GH docker action
Being able to functionaly utilize the same GH Docker action can be
beneficial for users wanting to build, test and develop in their own
repos. To do so, use ${{ github.repository_owner }} in the action. That
should provide some rudimentary flexibility without breaking the
canonical repo.

Users of this functionality should take care to populate the required
secrets in Github

* DOCKERHUB_TOKEN, DOCKERHUB_USERNAME
* CR_PAT
2022-07-09 19:06:33 -07:00
Frédéric Guillot abe568b5b3 Proxify empty URL should not crash 2022-07-05 21:20:03 -07:00
Frédéric Guillot c0eab5ebc5 Avoid stretched image if specified width is larger than Miniflux's layout 2022-07-04 20:10:07 -07:00
Frédéric Guillot f0a698c6fe Add support for OPML files with several nested outlines 2022-07-04 16:02:49 -07:00
Frédéric Guillot 806a069785 sanitizer: handle image URLs in srcset attribute with comma 2022-07-04 13:50:09 -07:00
Frédéric Guillot d85908e3de Allow width and height attributes for img tags 2022-07-03 17:44:12 -07:00
dependabot[bot] 9c6ea92122 Bump github.com/tdewolff/minify/v2 from 2.11.10 to 2.11.11
Bumps [github.com/tdewolff/minify/v2](https://github.com/tdewolff/minify) from 2.11.10 to 2.11.11.
- [Release notes](https://github.com/tdewolff/minify/releases)
- [Commits](https://github.com/tdewolff/minify/compare/v2.11.10...v2.11.11)

---
updated-dependencies:
- dependency-name: github.com/tdewolff/minify/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-02 05:35:26 -07:00
Alexandros Kosiaris 229774d65d Document that -config-dump shows sensitive info
Why:
Avoid surprising users that may not expect that passwords might be
printed in the config dump output

What:
Update manpage
2022-06-27 17:43:23 +02:00
dependabot[bot] aba2f83371 Bump github.com/tdewolff/minify/v2 from 2.11.9 to 2.11.10
Bumps [github.com/tdewolff/minify/v2](https://github.com/tdewolff/minify) from 2.11.9 to 2.11.10.
- [Release notes](https://github.com/tdewolff/minify/releases)
- [Commits](https://github.com/tdewolff/minify/compare/v2.11.9...v2.11.10)

---
updated-dependencies:
- dependency-name: github.com/tdewolff/minify/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-27 17:42:04 +02:00
Marcus Rohrmoser 69dca2b619 System-V init service. 2022-06-14 21:45:43 +02:00
dependabot[bot] fc4bfb2dc1 Bump github.com/tdewolff/minify/v2 from 2.11.7 to 2.11.9
Bumps [github.com/tdewolff/minify/v2](https://github.com/tdewolff/minify) from 2.11.7 to 2.11.9.
- [Release notes](https://github.com/tdewolff/minify/releases)
- [Commits](https://github.com/tdewolff/minify/compare/v2.11.7...v2.11.9)

---
updated-dependencies:
- dependency-name: github.com/tdewolff/minify/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-07 21:40:24 +02:00
Pk11 a904c634b8 request_builder.js: Fix syntax error 2022-06-06 10:22:41 +02:00
dependabot[bot] 938ae6828c Bump github.com/tdewolff/minify/v2 from 2.11.5 to 2.11.7
Bumps [github.com/tdewolff/minify/v2](https://github.com/tdewolff/minify) from 2.11.5 to 2.11.7.
- [Release notes](https://github.com/tdewolff/minify/releases)
- [Commits](https://github.com/tdewolff/minify/compare/v2.11.5...v2.11.7)

---
updated-dependencies:
- dependency-name: github.com/tdewolff/minify/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-02 15:37:51 +02:00
Frédéric Guillot 79df37ac1e Fix RPM Dockerfile packager 2022-05-27 20:47:14 -07:00
Frédéric Guillot f546fc3060 Fix typo 2022-05-27 20:46:41 -07:00
567 changed files with 14067 additions and 7326 deletions
+24
View File
@@ -0,0 +1,24 @@
{
"name": "Miniflux",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspace",
"remoteUser": "vscode",
"forwardPorts": [
8080
],
"customizations": {
"vscode": {
"settings": {
"go.toolsManagement.checkForUpdates": "local",
"go.useLanguageServer": true,
"go.gopath": "/go"
},
"extensions": [
"ms-azuretools.vscode-docker",
"golang.go",
"rangav.vscode-thunder-client"
]
}
}
}
+31
View File
@@ -0,0 +1,31 @@
version: '3.8'
services:
app:
image: mcr.microsoft.com/devcontainers/go
volumes:
- ..:/workspace:cached
command: sleep infinity
network_mode: service:db
environment:
- CREATE_ADMIN=1
- ADMIN_USERNAME=admin
- ADMIN_PASSWORD=test123
db:
image: postgres:15
restart: unless-stopped
volumes:
- postgres-data:/var/lib/postgresql/data
hostname: postgres
environment:
POSTGRES_DB: miniflux2
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_HOST_AUTH_METHOD: trust
ports:
- 5432:5432
apprise:
image: caronc/apprise:latest
restart: unless-stopped
hostname: apprise
volumes:
postgres-data: null
+1 -1
View File
@@ -2,7 +2,7 @@
name: Bug report
about: Create a bug report
title: ''
labels: bug
labels: bug, triage needed
assignees: ''
---
+1 -1
View File
@@ -2,7 +2,7 @@
name: Feed Problems
about: Problems with a feed or a website
title: ''
labels: feed problems
labels: feed problems, triage needed
assignees: ''
---
@@ -1,10 +0,0 @@
---
name: Installation Issue
about: Do you need help to install Miniflux?
title: ''
labels: installation issue
assignees: ''
---
@@ -1,10 +0,0 @@
---
name: Question / Discussion
about: Open discussions
title: ''
labels: question / discussion
assignees: ''
---
+2
View File
@@ -0,0 +1,2 @@
paths-ignore:
- ./http/client/testdata
+36
View File
@@ -2,6 +2,15 @@ version: 2
updates:
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "daily"
reviewers:
- "fguillot"
assignees:
- "fguillot"
- package-ecosystem: "docker"
directory: "/packaging/docker/alpine"
schedule:
interval: "weekly"
reviewers:
@@ -10,6 +19,33 @@ updates:
- "fguillot"
- package-ecosystem: "docker"
directory: "/packaging/docker/distroless"
schedule:
interval: "weekly"
reviewers:
- "fguillot"
assignees:
- "fguillot"
- package-ecosystem: "docker"
directory: "packaging/debian"
schedule:
interval: "weekly"
reviewers:
- "fguillot"
assignees:
- "fguillot"
- package-ecosystem: "docker"
directory: "packaging/rpm"
schedule:
interval: "weekly"
reviewers:
- "fguillot"
assignees:
- "fguillot"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
+7 -37
View File
@@ -1,24 +1,13 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
permissions: read-all
on:
push:
branches: [ master ]
branches: [ main ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
branches: [ main ]
schedule:
- cron: '45 22 * * 3'
@@ -35,38 +24,19 @@ jobs:
fail-fast: false
matrix:
language: [ 'go', 'javascript' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://git.io/codeql-language-support
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
config-file: ./.github/codeql/config.yml
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
uses: github/codeql-action/autobuild@v2
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v2
+55
View File
@@ -0,0 +1,55 @@
name: Debian Packages
permissions: read-all
on:
push:
tags:
- '[0-9]+.[0-9]+.[0-9]+'
pull_request:
branches: [ main ]
jobs:
test-packages:
if: github.event.pull_request
name: Test Packages
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
id: buildx
with:
install: true
- name: Available Docker Platforms
run: echo ${{ steps.buildx.outputs.platforms }}
- name: Build Debian Packages
run: make debian-packages
- name: List generated files
run: ls -l *.deb
publish-packages:
if: ${{ ! github.event.pull_request }}
name: Publish Packages
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
id: buildx
with:
install: true
- name: Available Docker Platforms
run: echo ${{ steps.buildx.outputs.platforms }}
- name: Build Debian Packages
run: make debian-packages
- name: List generated files
run: ls -l *.deb
- name: Upload packages to repository
env:
FURY_TOKEN: ${{ secrets.FURY_TOKEN }}
run: for f in *.deb; do curl -F package=@$f https://$FURY_TOKEN@push.fury.io/miniflux/; done
+55 -17
View File
@@ -1,69 +1,107 @@
name: Docker
permissions: read-all
on:
schedule:
- cron: '0 1 * * *'
push:
tags:
- '*.*.*'
- '[0-9]+.[0-9]+.[0-9]+'
pull_request:
branches: [ main ]
jobs:
docker-images:
test-docker-images:
if: github.event.pull_request
name: Test Images
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Build Alpine image
uses: docker/build-push-action@v4
with:
context: .
file: ./packaging/docker/alpine/Dockerfile
push: false
tags: ${{ github.repository_owner }}/miniflux:alpine-dev
- name: Test Alpine Docker image
run: docker run --rm ${{ github.repository_owner }}/miniflux:alpine-dev miniflux -i
- name: Build Distroless image
uses: docker/build-push-action@v4
with:
context: .
file: ./packaging/docker/distroless/Dockerfile
push: false
tags: ${{ github.repository_owner }}/miniflux:distroless-dev
- name: Test Distroless Docker image
run: docker run --rm ${{ github.repository_owner }}/miniflux:distroless-dev miniflux -i
publish-docker-images:
if: ${{ ! github.event.pull_request }}
name: Publish Images
permissions:
packages: write
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Generate Alpine Docker tag
id: docker_alpine_tag
run: |
DOCKER_IMAGE=miniflux/miniflux
DOCKER_IMAGE=${{ github.repository_owner }}/miniflux
DOCKER_VERSION=dev
if [ "${{ github.event_name }}" = "schedule" ]; then
DOCKER_VERSION=nightly
TAGS="${DOCKER_IMAGE}:${DOCKER_VERSION},ghcr.io/${DOCKER_IMAGE}:${DOCKER_VERSION}"
TAGS="docker.io/${DOCKER_IMAGE}:${DOCKER_VERSION},ghcr.io/${DOCKER_IMAGE}:${DOCKER_VERSION},quay.io/${DOCKER_IMAGE}:${DOCKER_VERSION}"
elif [[ $GITHUB_REF == refs/tags/* ]]; then
DOCKER_VERSION=${GITHUB_REF#refs/tags/}
TAGS="${DOCKER_IMAGE}:${DOCKER_VERSION},ghcr.io/${DOCKER_IMAGE}:${DOCKER_VERSION},${DOCKER_IMAGE}:latest,ghcr.io/${DOCKER_IMAGE}:latest"
TAGS="docker.io/${DOCKER_IMAGE}:${DOCKER_VERSION},ghcr.io/${DOCKER_IMAGE}:${DOCKER_VERSION},quay.io/${DOCKER_IMAGE}:${DOCKER_VERSION},docker.io/${DOCKER_IMAGE}:latest,ghcr.io/${DOCKER_IMAGE}:latest,quay.io/${DOCKER_IMAGE}:latest"
fi
echo ::set-output name=tags::${TAGS}
- name: Generate Distroless Docker tag
id: docker_distroless_tag
run: |
DOCKER_IMAGE=miniflux/miniflux
DOCKER_IMAGE=${{ github.repository_owner }}/miniflux
DOCKER_VERSION=dev-distroless
if [ "${{ github.event_name }}" = "schedule" ]; then
DOCKER_VERSION=nightly-distroless
TAGS="${DOCKER_IMAGE}:${DOCKER_VERSION},ghcr.io/${DOCKER_IMAGE}:${DOCKER_VERSION}"
TAGS="docker.io/${DOCKER_IMAGE}:${DOCKER_VERSION},ghcr.io/${DOCKER_IMAGE}:${DOCKER_VERSION},quay.io/${DOCKER_IMAGE}:${DOCKER_VERSION}"
elif [[ $GITHUB_REF == refs/tags/* ]]; then
DOCKER_VERSION=${GITHUB_REF#refs/tags/}-distroless
TAGS="${DOCKER_IMAGE}:${DOCKER_VERSION},ghcr.io/${DOCKER_IMAGE}:${DOCKER_VERSION},${DOCKER_IMAGE}:latest-distroless,ghcr.io/${DOCKER_IMAGE}:latest-distroless"
TAGS="docker.io/${DOCKER_IMAGE}:${DOCKER_VERSION},ghcr.io/${DOCKER_IMAGE}:${DOCKER_VERSION},quay.io/${DOCKER_IMAGE}:${DOCKER_VERSION},docker.io/${DOCKER_IMAGE}:latest-distroless,ghcr.io/${DOCKER_IMAGE}:latest-distroless,quay.io/${DOCKER_IMAGE}:latest-distroless"
fi
echo ::set-output name=tags::${TAGS}
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v2
- name: Login to DockerHub
uses: docker/login-action@v1
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v1
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.CR_PAT }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to Quay Container Registry
uses: docker/login-action@v2
with:
registry: quay.io
username: ${{ secrets.QUAY_USERNAME }}
password: ${{ secrets.QUAY_TOKEN }}
- name: Build and Push Alpine images
uses: docker/build-push-action@v2
uses: docker/build-push-action@v4
with:
context: .
file: ./packaging/docker/alpine/Dockerfile
@@ -72,7 +110,7 @@ jobs:
tags: ${{ steps.docker_alpine_tag.outputs.tags }}
- name: Build and Push Distroless images
uses: docker/build-push-action@v2
uses: docker/build-push-action@v4
with:
context: .
file: ./packaging/docker/distroless/Dockerfile
+7 -8
View File
@@ -4,14 +4,14 @@ permissions: read-all
on:
pull_request:
branches:
- master
- main
jobs:
jshint:
name: Javascript Linter
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Install jshint
run: |
sudo npm install -g jshint@2.13.3
@@ -22,11 +22,10 @@ jobs:
name: Golang Linter
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: 1.17
- uses: golangci/golangci-lint-action@v2
go-version: "1.21"
- uses: golangci/golangci-lint-action@v3
with:
args: --skip-dirs tests --disable errcheck --enable sqlclosecheck --enable misspell --enable gofmt --enable goimports --enable whitespace
skip-go-installation: true
args: --timeout 10m --skip-dirs tests --disable errcheck --enable sqlclosecheck --enable misspell --enable gofmt --enable goimports --enable whitespace
+37
View File
@@ -0,0 +1,37 @@
name: RPM Packages
permissions: read-all
on:
push:
tags:
- '[0-9]+.[0-9]+.[0-9]+'
pull_request:
branches: [ main ]
jobs:
test-package:
if: github.event.pull_request
name: Test Packages
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Build RPM Package
run: make rpm
- name: List generated files
run: ls -l *.rpm
publish-package:
if: ${{ ! github.event.pull_request }}
name: Publish Packages
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Build RPM Package
run: make rpm
- name: List generated files
run: ls -l *.rpm
- name: Upload package to repository
env:
FURY_TOKEN: ${{ secrets.FURY_TOKEN }}
run: for f in *.rpm; do curl -F package=@$f https://$FURY_TOKEN@push.fury.io/miniflux/; done
-55
View File
@@ -1,55 +0,0 @@
name: Scorecards supply-chain security
on:
# Only the default branch is supported.
branch_protection_rule:
schedule:
- cron: '31 8 * * 6'
push:
branches: [ master ]
# Declare default permissions as read only.
permissions: read-all
jobs:
analysis:
name: Scorecards analysis
runs-on: ubuntu-latest
permissions:
# Needed to upload the results to code-scanning dashboard.
security-events: write
actions: read
contents: read
steps:
- name: "Checkout code"
uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579 # v2.4.0
with:
persist-credentials: false
- name: "Run analysis"
uses: ossf/scorecard-action@e3e75cf2ffbf9364bbff86cdbdf52b23176fe492 # v1.0.1
with:
results_file: results.sarif
results_format: sarif
# Read-only PAT token. To create it,
# follow the steps in https://github.com/ossf/scorecard-action#pat-token-creation.
repo_token: ${{ secrets.SCORECARD_READ_TOKEN }}
# Publish the results to enable scorecard badges. For more details, see
# https://github.com/ossf/scorecard-action#publishing-results.
# For private repositories, `publish_results` will automatically be set to `false`,
# regardless of the value entered here.
publish_results: true
# Upload the results as artifacts (optional).
- name: "Upload artifact"
uses: actions/upload-artifact@82c141cc518b40d92cc801eee768e7aafc9c2fa2 # v2.3.1
with:
name: SARIF file
path: results.sarif
retention-days: 5
# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@5f532563584d71fdef14ee64d17bafb34f751ce5 # v1.0.26
with:
sarif_file: results.sarif
@@ -1,10 +1,10 @@
name: CI Workflow
name: Tests
permissions: read-all
on:
pull_request:
branches:
- master
- main
jobs:
unit-tests:
@@ -14,14 +14,14 @@ jobs:
max-parallel: 4
matrix:
os: [ubuntu-latest, windows-latest, macOS-latest]
go-version: [1.16, 1.17, 1.18]
go-version: ["1.21"]
steps:
- name: Set up Go
uses: actions/setup-go@v2
uses: actions/setup-go@v4
with:
go-version: ${{ matrix.go-version }}
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Run unit tests
run: make test
@@ -40,13 +40,13 @@ jobs:
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
steps:
- name: Set up Go
uses: actions/setup-go@v2
uses: actions/setup-go@v4
with:
go-version: 1.16
go-version: "1.21"
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Install Postgres client
run: sudo apt-get install -y postgresql-client
run: sudo apt update && sudo apt install -y postgresql-client
- name: Run integration tests
run: make integration-test
env:
+2 -1
View File
@@ -2,4 +2,5 @@ miniflux-*
miniflux
*.rpm
*.deb
.idea
.idea
.vscode
+248 -1
View File
@@ -1,3 +1,250 @@
Version 2.0.47 (August 20, 2023)
--------------------------------
* Update rules for `webtoons.com`
* Use HTTP client from the standard library for third-party integrations
* Rename internal `url` package to `urllib` to avoid overlap with `net/url`
* Add Shaarli integration
* Add Shiori integration
* Add Apprise integration
* Consider base path when generating third-party services API endpoint
* Use podcast duration tag as reading time
* Move internal packages to an `internal` folder
* For reference: <https://go.dev/doc/go1.4#internalpackages>
* Rename Miniflux package name to follow Go module naming convention
* For reference: <https://go.dev/ref/mod#major-version-suffixes>
* Update RockyLinux image from 8 to 9 (used to build RPM package)
* Add force refresh in feed edit and feed entries page
* Use Odysee video duration as read time
* Upgrade to Go 1.21
* Use details disclosure element to show the list of third-party services
* Use Web Share API for sharing entry
* Add a workaround for parsing some invalid date format
* Add Thunder Client API collection into contrib folder
* Add new API endpoint: `/entries/{entryID}/save`
* Trigger Docker and packages workflows only for semantic tags
* Go module versioning expect Git tags to start with the letter v.
* The goal is to keep the existing naming convention for generated artifacts and
have proper versioning for the Go module.
* Bump `golang.org/x/*` dependencies
* Bump `github.com/yuin/goldmark`
* Bump `github.com/tdewolff/minify/v2`
* Bump `github.com/mccutchen/go-httpbin/v2`
Version 2.0.46 (July 21, 2023)
------------------------------
* Add scraper and rewrite rules for Webtoons
* Fix regression in integration page and simplify SQL query
* Wallabag integration: add more information in log messages
* Add support for custom Youtube embed URL
* Fix accessibility issues in modal component
* Fix modal aria role
* Trap focusing with tab / shift+tab inside the modal
* Restore keyboard focus when closing modal
* Automatically move keyboard focus to first focusable element unless specified otherwise
* Keyboard shortcut help modal: move keyboard focus to modal title
* Keyboard shortcut help modal: change close control from link to button
* Add Notion integration
* Update `golang.org/x/*` dependencies and `go-oidc` to v3.6.0
* Improve responsive design
* Add user setting for marking entry as read on view
* Improve Russian translation
* Add the possibility to run cleanup tasks from the command line
* Add the possibility to run Miniflux as a cronjob
* Use `go-httpbin` to run tests locally and avoid remote calls to `httpbin.org`
* Display tags when viewing entries
* Update categories API endpoint to return `total_unread` and `feed_count`
* Improve date parser to handle various broken date formats
* Avoid `pq: time zone displacement out of range` errors
* Improve entry existance check to make better use of index
* Add unique index `enclosures_user_entry_url_idx`
* Add mark as unread for Linkding integration
* Add sub-folder support for Wallabag integration
* Use RockyLinux to build RPM package
* Disable CGO when building RPM package
* Disable CGO when building Docker images
Version 2.0.45 (June 21, 2023)
------------------------------
* Add media player to listen to audio and video podcasts with the possiblity to resume to last playback position
* Add default tag names for Linkding integration
* Mark only globally visible entries when marking all entries from UI
* Use image included in feed as feed icon when available
* Order history by `changed_at` and `published_at`
* Remove title attribute from entry title links
* Fix reading time that is not aligned correctly with the latest version of Safari
* Use glyphs of the same size on keyboard shortcuts page
* Add maskable versions of the PWA icon
* Replace copyright header with SPDX identifier
* Remove the "í" letter from the Portuguese "lido" word
* Increase golangci-lint timeout value
* Bump `github.com/tdewolff/minify/v2`, `github.com/prometheus/client_golang`, `golang.org/x/*` dependencies
Version 2.0.44 (May 6, 2023)
----------------------------
* Add link to the URL rewrite rules documentation
* Update scraping rules for `ilpost.it`
* Update rewrite rules for `theverge.com`
* Add a rewrite rule to remove clickbait titles
* Make sure `PROXY_IMAGES` option is backward compatible with `PROXY_OPTION` and `PROXY_MEDIA_TYPES`
* Add new rule to remove tables
* Add support for searching well-known URLs in subdirectory
* Add CSS `word-wrap` rule to break very long entry title into multiple lines
* Add swipe as option for gesture navigation between entries. There are now 3 possible choices: `none`, `double-tap`, and `swipe`.
* Prefer typographic punctuation in English translation
* Process older entries first:
- Feed entries are usually ordered from most to least recent.
- Processing older entries first ensures that their creation timestamp
is lower than that of newer entries.
- This is useful when we order by creation, because then we get a
consistent timeline.
* Fix Grafana dashboard
* Push Docker images to `Quay.io` (RedHat)
* Bump `golang.org/x/*`, `github.com/lib/pq`, `mvdan.cc/xurls/v2` and `github.com/prometheus/client_golang` dependencies
Version 2.0.43 (March 16, 2023)
-------------------------------
* Avoid XSS when opening a broken image due to unescaped ServerError in proxy handler (CVE-2023-27592)
Creating an RSS feed item with the inline description containing an `<img>` tag
with a `srcset` attribute pointing to an invalid URL like
`http:a<script>alert(1)</script>`, we can coerce the proxy handler into an error
condition where the invalid URL is returned unescaped and in full.
This results in JavaScript execution on the Miniflux instance as soon as the
user is convinced to open the broken image.
* Use `r.RemoteAddr` to check `/metrics` endpoint network access (CVE-2023-27591)
HTTP headers like `X-Forwarded-For` or `X-Real-Ip` can be easily spoofed. As
such, it cannot be used to test if the client IP is allowed.
The recommendation is to use HTTP Basic authentication to protect the
metrics endpoint, or run Miniflux behind a trusted reverse-proxy.
* Add HTTP Basic authentication for `/metrics` endpoint
* Add proxy support for several media types
* Parse feed categories from RSS, Atom and JSON feeds
* Ignore empty link when discovering feeds
* Disable CGO explicitly to make sure the binary is statically linked
* Add CSS classes to differentiate between category/feed/entry view and icons
* Add rewrite and scraper rules for `blog.cloudflare.com`
* Add `color-scheme` to themes
* Add new keyboard shortcut to toggle open/close entry attachments section
* Sanitizer: allow `id` attribute in `<sup>` element
* Add Indonesian Language
* Update translations
* Update Docker Compose examples:
- Run the application in one command
- Bring back the health check condition to `depends_on`
- Remove deprecated `version` element
* Update scraping rules for `ilpost.it`
* Bump `github.com/PuerkitoBio/goquery` from `1.8.0` to `1.8.1`
* Bump `github.com/tdewolff/minify/v2` from `2.12.4` to `2.12.5`
* Bump `github.com/yuin/goldmark` from `1.5.3` to `1.5.4`
* Bump `golang.org/x/*` dependencies
Version 2.0.42 (January 29, 2023)
---------------------------------
* Fix header items wrapping
* Add option to enable or disable double tap
* Improve PWA display mode label in settings page
* Bump `golang.org/x/*` dependencies
* Update translations
* Add scraping rule for `ilpost.it`
* Update reading time HTML element after fetching the original web page
* Add category feeds refresh feature
Version 2.0.41 (December 10, 2022)
----------------------------------
* Reverted PR #1290 (follow the only link) because it leads to several panics/segfaults that prevent feed updates
* Disable double-tap mobile gesture if swipe gesture is disabled
* Skip integrations if there are no entries to push
* Enable TLS-ALPN-01 challenge for ACME
- This type of challenge works purely at the TLS layer and is compatible
with SNI proxies. The existing HTTP-01 challenge support has been left
as-is.
* Preconfigure Miniflux for GitHub Codespaces
* Updated `golang.org/x/net/*` dependencies
Version 2.0.40 (November 13, 2022)
----------------------------------
* Update dependencies
* Pin Postgres image version in Docker Compose examples to avoid unexpected upgrades
* Make English and Spanish translation more consistent:
- Use "Feed" everywhere instead of "Subscription"
- Use "Entry" instead of "Article"
* Allow Content-Type and Accept headers in CORS policy
* Use dirs file for Debian package
* Use custom home page in PWA manifest
* Fix scraper rule that could be incorrect when there is a redirect
* Improve web scraper to fetch the only link present as workaround to some landing pages
* Add Matrix bot integration
* Proxify images in API responses
* Add new options in user preferences to configure sorting of entries in the category page
* Remove dependency on `github.com/mitchellh/go-server-timing`
* Add support for the `continuation` parameter and result for Google Reader API ID calls
* Use automatic variable for build target file names
* Add rewrite rule for `recalbox.com`
* Improve Dutch translation
Version 2.0.39 (October 16, 2022)
---------------------------------
* Add support for date filtering in Google Reader API item ID calls
* Handle RSS entries with only a GUID permalink
* Go API Client: Accept endpoint URLs ending with `/v1/`
* CORS API headers: Allow `Basic` authorization header
* Log feed URL when submitting a subscription that returns an error
* Update `make run` command to execute migrations automatically
* Add option to send only the URL to Wallabag
* Do not convert anchors to absolute links
* Add config option to use a custom image proxy URL
* Allow zoom on mobile devices
* Add scraping rules for `theverge.com`, `royalroad.com`, `swordscomic.com`, and `smbc-comics.com`
* Add Ukrainian translation
* Update `golang.org/x/*` dependencies
* Bump `github.com/tdewolff/minify/v2` from `2.12.0` to `2.12.4`
* Bump `github.com/yuin/goldmark` from `1.4.13` to `1.5.2`
* Bump `github.com/lib/pq` from `1.10.6` to `1.10.7`
Version 2.0.38 (August 13, 2022)
--------------------------------
* Rename default branch from master to main
* Update GitHub Actions
* Bump `github.com/prometheus/client_golang` from `1.12.2` to `1.13.0`
* Fix some linter issues
* Handle Atom links with a text/html type defined
* Add `parse_markdown` rewrite function
* Build RPM and Debian packages automatically using GitHub Actions
* Add `explosm.net` scraper rule
* Make default home page configurable
* Add title attribute to entry links because text could be truncated
* Highlight categories with unread entries
* Allow option to order by title and author in API entry endpoint
* Update Russian translation
* Make reading speed user-configurable
* Added translation for Hindi language used in India
* Add rewrite rules for article URL before fetching content
* Bump `github.com/tdewolff/minify/v2` from `2.11.7` to `2.12.0`
* Support other repo owners in GitHub Docker Action
* Proxify empty URL should not crash
* Avoid stretched image if specified width is larger than Miniflux's layout
* Add support for OPML files with several nested outlines
* sanitizer: handle image URLs in `srcset` attribute with comma
* Allow `width` and `height` attributes for `img` tags
* Document that `-config-dump` command line argument shows sensitive info
* Add System-V init service in contrib folder
* Fix syntax error in `RequestBuilder.getCsrfToken()` method
Version 2.0.37 (May 27, 2022)
-----------------------------
@@ -21,7 +268,7 @@ Version 2.0.37 (May 27, 2022)
* Add distroless Docker image variant
* Add Go 1.18 to GitHub Action
* Bump `github.com/tdewolff/minify/v2` from `2.10.0` to `2.11`
* Bump `github.com/prometheus/client_golan` from `1.12.1` to `1.12.2`
* Bump `github.com/prometheus/client_golang` from `1.12.1` to `1.12.2`
* Bump `github.com/lib/pq` from `1.10.4` to `1.10.6`
Version 2.0.36 (March 8, 2022)
+21 -21
View File
@@ -3,7 +3,7 @@ DOCKER_IMAGE := miniflux/miniflux
VERSION := $(shell git describe --tags --abbrev=0)
COMMIT := $(shell git rev-parse --short HEAD)
BUILD_DATE := `date +%FT%T%z`
LD_FLAGS := "-s -w -X 'miniflux.app/version.Version=$(VERSION)' -X 'miniflux.app/version.Commit=$(COMMIT)' -X 'miniflux.app/version.BuildDate=$(BUILD_DATE)'"
LD_FLAGS := "-s -w -X 'miniflux.app/v2/internal/version.Version=$(VERSION)' -X 'miniflux.app/v2/internal/version.Commit=$(COMMIT)' -X 'miniflux.app/v2/internal/version.BuildDate=$(BUILD_DATE)'"
PKG_LIST := $(shell go list ./... | grep -v /vendor/)
DB_URL := postgres://postgres:postgres@localhost/miniflux_test?sslmode=disable
DEB_IMG_ARCH := amd64
@@ -43,61 +43,61 @@ export PGPASSWORD := postgres
debian-packages
miniflux:
@ go build -buildmode=pie -ldflags=$(LD_FLAGS) -o $(APP) main.go
@ CGO_ENABLED=0 go build -buildmode=pie -ldflags=$(LD_FLAGS) -o $(APP) main.go
linux-amd64:
@ GOOS=linux GOARCH=amd64 go build -ldflags=$(LD_FLAGS) -o $(APP)-linux-amd64 main.go
@ CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags=$(LD_FLAGS) -o $(APP)-$@ main.go
linux-arm64:
@ GOOS=linux GOARCH=arm64 go build -ldflags=$(LD_FLAGS) -o $(APP)-linux-arm64 main.go
@ CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags=$(LD_FLAGS) -o $(APP)-$@ main.go
linux-armv7:
@ GOOS=linux GOARCH=arm GOARM=7 go build -ldflags=$(LD_FLAGS) -o $(APP)-linux-armv7 main.go
@ CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build -ldflags=$(LD_FLAGS) -o $(APP)-$@ main.go
linux-armv6:
@ GOOS=linux GOARCH=arm GOARM=6 go build -ldflags=$(LD_FLAGS) -o $(APP)-linux-armv6 main.go
@ CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=6 go build -ldflags=$(LD_FLAGS) -o $(APP)-$@ main.go
linux-armv5:
@ GOOS=linux GOARCH=arm GOARM=5 go build -ldflags=$(LD_FLAGS) -o $(APP)-linux-armv5 main.go
@ CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=5 go build -ldflags=$(LD_FLAGS) -o $(APP)-$@ main.go
darwin-amd64:
@ GOOS=darwin GOARCH=amd64 go build -ldflags=$(LD_FLAGS) -o $(APP)-darwin-amd64 main.go
@ GOOS=darwin GOARCH=amd64 go build -ldflags=$(LD_FLAGS) -o $(APP)-$@ main.go
darwin-arm64:
@ GOOS=darwin GOARCH=arm64 go build -ldflags=$(LD_FLAGS) -o $(APP)-darwin-arm64 main.go
@ GOOS=darwin GOARCH=arm64 go build -ldflags=$(LD_FLAGS) -o $(APP)-$@ main.go
freebsd-amd64:
@ GOOS=freebsd GOARCH=amd64 go build -ldflags=$(LD_FLAGS) -o $(APP)-freebsd-amd64 main.go
@ CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 go build -ldflags=$(LD_FLAGS) -o $(APP)-$@ main.go
openbsd-amd64:
@ GOOS=openbsd GOARCH=amd64 go build -ldflags=$(LD_FLAGS) -o $(APP)-openbsd-amd64 main.go
@ GOOS=openbsd GOARCH=amd64 go build -ldflags=$(LD_FLAGS) -o $(APP)-$@ main.go
windows-amd64:
@ GOOS=windows GOARCH=amd64 go build -ldflags=$(LD_FLAGS) -o $(APP)-windows-amd64 main.go
@ GOOS=windows GOARCH=amd64 go build -ldflags=$(LD_FLAGS) -o $(APP)-$@ main.go
build: linux-amd64 linux-arm64 linux-armv7 linux-armv6 linux-armv5 darwin-amd64 darwin-arm64 freebsd-amd64 openbsd-amd64 windows-amd64
# NOTE: unsupported targets
netbsd-amd64:
@ GOOS=netbsd GOARCH=amd64 go build -ldflags=$(LD_FLAGS) -o $(APP)-netbsd-amd64 main.go
@ CGO_ENABLED=0 GOOS=netbsd GOARCH=amd64 go build -ldflags=$(LD_FLAGS) -o $(APP)-$@ main.go
linux-x86:
@ GOOS=linux GOARCH=386 go build -ldflags=$(LD_FLAGS) -o $(APP)-linux-x86 main.go
@ CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -ldflags=$(LD_FLAGS) -o $(APP)-$@ main.go
freebsd-x86:
@ GOOS=freebsd GOARCH=386 go build -ldflags=$(LD_FLAGS) -o $(APP)-freebsd-x86 main.go
@ CGO_ENABLED=0 GOOS=freebsd GOARCH=386 go build -ldflags=$(LD_FLAGS) -o $(APP)-$@ main.go
netbsd-x86:
@ GOOS=netbsd GOARCH=386 go build -ldflags=$(LD_FLAGS) -o $(APP)-netbsd-x86 main.go
@ CGO_ENABLED=0 GOOS=netbsd GOARCH=386 go build -ldflags=$(LD_FLAGS) -o $(APP)-$@ main.go
openbsd-x86:
@ GOOS=openbsd GOARCH=386 go build -ldflags=$(LD_FLAGS) -o $(APP)-freebsd-x86 main.go
@ GOOS=openbsd GOARCH=386 go build -ldflags=$(LD_FLAGS) -o $(APP)-$@ main.go
windows-x86:
@ GOOS=windows GOARCH=386 go build -ldflags=$(LD_FLAGS) -o $(APP)-windows-x86 main.go
@ GOOS=windows GOARCH=386 go build -ldflags=$(LD_FLAGS) -o $(APP)-$@ main.go
run:
@ LOG_DATE_TIME=1 go run main.go -debug
@ LOG_DATE_TIME=1 DEBUG=1 RUN_MIGRATIONS=1 CREATE_ADMIN=1 ADMIN_USERNAME=admin ADMIN_PASSWORD=test123 go run main.go
clean:
@ rm -f $(APP)-* $(APP) $(APP)*.rpm $(APP)*.deb
@@ -122,7 +122,7 @@ integration-test:
./miniflux-test >/tmp/miniflux.log 2>&1 & echo "$$!" > "/tmp/miniflux.pid"
while ! nc -z localhost 8080; do sleep 1; done
go test -v -tags=integration -count=1 miniflux.app/tests
go test -v -tags=integration -count=1 miniflux.app/v2/internal/tests
clean-integration-test:
@ kill -9 `cat /tmp/miniflux.pid`
@@ -153,7 +153,7 @@ rpm: clean
rpmbuild -bb --define "_miniflux_version $(VERSION)" /root/rpmbuild/SPECS/miniflux.spec
debian:
@ docker build \
@ docker build --load \
--build-arg BASE_IMAGE_ARCH=$(DEB_IMG_ARCH) \
-t $(DEB_IMG_ARCH)/miniflux-deb-builder \
-f packaging/debian/Dockerfile \
+3 -1
View File
@@ -6,4 +6,6 @@ Only the latest stable version is supported.
## Reporting a Vulnerability
Send an email to `security AT miniflux DOT net` with all the steps to reproduce the problem.
Preferably, [report the vulnerability privately using GitHub](https://github.com/miniflux/v2/security/advisories/new) ([documentation](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing/privately-reporting-a-security-vulnerability)).
If you do not want to use GitHub, send an email to `security AT miniflux DOT net` with all the steps to reproduce the problem.
-10
View File
@@ -1,10 +0,0 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
/*
Package cli implements command line arguments for Miniflux application.
*/
package cli // import "miniflux.app/cli"
+3 -3
View File
@@ -1,7 +1,7 @@
Miniflux API Client
===================
[![PkgGoDev](https://pkg.go.dev/badge/miniflux.app/client)](https://pkg.go.dev/miniflux.app/client)
[![PkgGoDev](https://pkg.go.dev/badge/miniflux.app/v2/client)](https://pkg.go.dev/miniflux.app/v2/client)
Client library for Miniflux REST API.
@@ -9,7 +9,7 @@ Installation
------------
```bash
go get -u miniflux.app/client
go get -u miniflux.app/v2/client
```
Example
@@ -22,7 +22,7 @@ import (
"fmt"
"os"
miniflux "miniflux.app/client"
miniflux "miniflux.app/v2/client"
)
func main() {
+43 -50
View File
@@ -1,8 +1,7 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package client // import "miniflux.app/client"
package client // import "miniflux.app/v2/client"
import (
"encoding/json"
@@ -10,6 +9,7 @@ import (
"io"
"net/url"
"strconv"
"strings"
)
// Client holds API procedure calls.
@@ -19,6 +19,11 @@ type Client struct {
// New returns a new Miniflux client.
func New(endpoint string, credentials ...string) *Client {
// Web gives "API Endpoint = https://miniflux.app/v1/", it doesn't work (/v1/v1/me)
endpoint = strings.TrimSuffix(endpoint, "/")
endpoint = strings.TrimSuffix(endpoint, "/v1")
// trim to https://miniflux.app
if len(credentials) == 2 {
return &Client{request: &request{endpoint: endpoint, username: credentials[0], password: credentials[1]}}
}
@@ -34,8 +39,7 @@ func (c *Client) Me() (*User, error) {
defer body.Close()
var user *User
decoder := json.NewDecoder(body)
if err := decoder.Decode(&user); err != nil {
if err := json.NewDecoder(body).Decode(&user); err != nil {
return nil, fmt.Errorf("miniflux: json error (%v)", err)
}
@@ -51,8 +55,7 @@ func (c *Client) Users() (Users, error) {
defer body.Close()
var users Users
decoder := json.NewDecoder(body)
if err := decoder.Decode(&users); err != nil {
if err := json.NewDecoder(body).Decode(&users); err != nil {
return nil, fmt.Errorf("miniflux: response error (%v)", err)
}
@@ -68,8 +71,7 @@ func (c *Client) UserByID(userID int64) (*User, error) {
defer body.Close()
var user User
decoder := json.NewDecoder(body)
if err := decoder.Decode(&user); err != nil {
if err := json.NewDecoder(body).Decode(&user); err != nil {
return nil, fmt.Errorf("miniflux: response error (%v)", err)
}
@@ -85,8 +87,7 @@ func (c *Client) UserByUsername(username string) (*User, error) {
defer body.Close()
var user User
decoder := json.NewDecoder(body)
if err := decoder.Decode(&user); err != nil {
if err := json.NewDecoder(body).Decode(&user); err != nil {
return nil, fmt.Errorf("miniflux: response error (%v)", err)
}
@@ -106,8 +107,7 @@ func (c *Client) CreateUser(username, password string, isAdmin bool) (*User, err
defer body.Close()
var user *User
decoder := json.NewDecoder(body)
if err := decoder.Decode(&user); err != nil {
if err := json.NewDecoder(body).Decode(&user); err != nil {
return nil, fmt.Errorf("miniflux: response error (%v)", err)
}
@@ -123,8 +123,7 @@ func (c *Client) UpdateUser(userID int64, userChanges *UserModificationRequest)
defer body.Close()
var u *User
decoder := json.NewDecoder(body)
if err := decoder.Decode(&u); err != nil {
if err := json.NewDecoder(body).Decode(&u); err != nil {
return nil, fmt.Errorf("miniflux: response error (%v)", err)
}
@@ -151,8 +150,7 @@ func (c *Client) Discover(url string) (Subscriptions, error) {
defer body.Close()
var subscriptions Subscriptions
decoder := json.NewDecoder(body)
if err := decoder.Decode(&subscriptions); err != nil {
if err := json.NewDecoder(body).Decode(&subscriptions); err != nil {
return nil, fmt.Errorf("miniflux: response error (%v)", err)
}
@@ -168,8 +166,7 @@ func (c *Client) Categories() (Categories, error) {
defer body.Close()
var categories Categories
decoder := json.NewDecoder(body)
if err := decoder.Decode(&categories); err != nil {
if err := json.NewDecoder(body).Decode(&categories); err != nil {
return nil, fmt.Errorf("miniflux: response error (%v)", err)
}
@@ -181,15 +178,13 @@ func (c *Client) CreateCategory(title string) (*Category, error) {
body, err := c.request.Post("/v1/categories", map[string]interface{}{
"title": title,
})
if err != nil {
return nil, err
}
defer body.Close()
var category *Category
decoder := json.NewDecoder(body)
if err := decoder.Decode(&category); err != nil {
if err := json.NewDecoder(body).Decode(&category); err != nil {
return nil, fmt.Errorf("miniflux: response error (%v)", err)
}
@@ -201,15 +196,13 @@ func (c *Client) UpdateCategory(categoryID int64, title string) (*Category, erro
body, err := c.request.Put(fmt.Sprintf("/v1/categories/%d", categoryID), map[string]interface{}{
"title": title,
})
if err != nil {
return nil, err
}
defer body.Close()
var category *Category
decoder := json.NewDecoder(body)
if err := decoder.Decode(&category); err != nil {
if err := json.NewDecoder(body).Decode(&category); err != nil {
return nil, fmt.Errorf("miniflux: response error (%v)", err)
}
@@ -231,8 +224,7 @@ func (c *Client) CategoryFeeds(categoryID int64) (Feeds, error) {
defer body.Close()
var feeds Feeds
decoder := json.NewDecoder(body)
if err := decoder.Decode(&feeds); err != nil {
if err := json.NewDecoder(body).Decode(&feeds); err != nil {
return nil, fmt.Errorf("miniflux: response error (%v)", err)
}
@@ -244,6 +236,12 @@ func (c *Client) DeleteCategory(categoryID int64) error {
return c.request.Delete(fmt.Sprintf("/v1/categories/%d", categoryID))
}
// RefreshCategory refreshes a category.
func (c *Client) RefreshCategory(categoryID int64) error {
_, err := c.request.Put(fmt.Sprintf("/v1/categories/%d/refresh", categoryID), nil)
return err
}
// Feeds gets all feeds.
func (c *Client) Feeds() (Feeds, error) {
body, err := c.request.Get("/v1/feeds")
@@ -253,8 +251,7 @@ func (c *Client) Feeds() (Feeds, error) {
defer body.Close()
var feeds Feeds
decoder := json.NewDecoder(body)
if err := decoder.Decode(&feeds); err != nil {
if err := json.NewDecoder(body).Decode(&feeds); err != nil {
return nil, fmt.Errorf("miniflux: response error (%v)", err)
}
@@ -292,8 +289,7 @@ func (c *Client) Feed(feedID int64) (*Feed, error) {
defer body.Close()
var feed *Feed
decoder := json.NewDecoder(body)
if err := decoder.Decode(&feed); err != nil {
if err := json.NewDecoder(body).Decode(&feed); err != nil {
return nil, fmt.Errorf("miniflux: response error (%v)", err)
}
@@ -313,8 +309,7 @@ func (c *Client) CreateFeed(feedCreationRequest *FeedCreationRequest) (int64, er
}
var r result
decoder := json.NewDecoder(body)
if err := decoder.Decode(&r); err != nil {
if err := json.NewDecoder(body).Decode(&r); err != nil {
return 0, fmt.Errorf("miniflux: response error (%v)", err)
}
@@ -369,8 +364,7 @@ func (c *Client) FeedIcon(feedID int64) (*FeedIcon, error) {
defer body.Close()
var feedIcon *FeedIcon
decoder := json.NewDecoder(body)
if err := decoder.Decode(&feedIcon); err != nil {
if err := json.NewDecoder(body).Decode(&feedIcon); err != nil {
return nil, fmt.Errorf("miniflux: response error (%v)", err)
}
@@ -386,8 +380,7 @@ func (c *Client) FeedEntry(feedID, entryID int64) (*Entry, error) {
defer body.Close()
var entry *Entry
decoder := json.NewDecoder(body)
if err := decoder.Decode(&entry); err != nil {
if err := json.NewDecoder(body).Decode(&entry); err != nil {
return nil, fmt.Errorf("miniflux: response error (%v)", err)
}
@@ -403,8 +396,7 @@ func (c *Client) CategoryEntry(categoryID, entryID int64) (*Entry, error) {
defer body.Close()
var entry *Entry
decoder := json.NewDecoder(body)
if err := decoder.Decode(&entry); err != nil {
if err := json.NewDecoder(body).Decode(&entry); err != nil {
return nil, fmt.Errorf("miniflux: response error (%v)", err)
}
@@ -420,8 +412,7 @@ func (c *Client) Entry(entryID int64) (*Entry, error) {
defer body.Close()
var entry *Entry
decoder := json.NewDecoder(body)
if err := decoder.Decode(&entry); err != nil {
if err := json.NewDecoder(body).Decode(&entry); err != nil {
return nil, fmt.Errorf("miniflux: response error (%v)", err)
}
@@ -439,8 +430,7 @@ func (c *Client) Entries(filter *Filter) (*EntryResultSet, error) {
defer body.Close()
var result EntryResultSet
decoder := json.NewDecoder(body)
if err := decoder.Decode(&result); err != nil {
if err := json.NewDecoder(body).Decode(&result); err != nil {
return nil, fmt.Errorf("miniflux: response error (%v)", err)
}
@@ -458,8 +448,7 @@ func (c *Client) FeedEntries(feedID int64, filter *Filter) (*EntryResultSet, err
defer body.Close()
var result EntryResultSet
decoder := json.NewDecoder(body)
if err := decoder.Decode(&result); err != nil {
if err := json.NewDecoder(body).Decode(&result); err != nil {
return nil, fmt.Errorf("miniflux: response error (%v)", err)
}
@@ -477,8 +466,7 @@ func (c *Client) CategoryEntries(categoryID int64, filter *Filter) (*EntryResult
defer body.Close()
var result EntryResultSet
decoder := json.NewDecoder(body)
if err := decoder.Decode(&result); err != nil {
if err := json.NewDecoder(body).Decode(&result); err != nil {
return nil, fmt.Errorf("miniflux: response error (%v)", err)
}
@@ -502,6 +490,12 @@ func (c *Client) ToggleBookmark(entryID int64) error {
return err
}
// SaveEntry sends an entry to a third-party service.
func (c *Client) SaveEntry(entryID int64) error {
_, err := c.request.Post(fmt.Sprintf("/v1/entries/%d/save", entryID), nil)
return err
}
// FetchCounters
func (c *Client) FetchCounters() (*FeedCounters, error) {
body, err := c.request.Get("/v1/feeds/counters")
@@ -511,8 +505,7 @@ func (c *Client) FetchCounters() (*FeedCounters, error) {
defer body.Close()
var result FeedCounters
decoder := json.NewDecoder(body)
if err := decoder.Decode(&result); err != nil {
if err := json.NewDecoder(body).Decode(&result); err != nil {
return nil, fmt.Errorf("miniflux: response error (%v)", err)
}
+5 -8
View File
@@ -1,17 +1,15 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
/*
Package client implements a client library for the Miniflux REST API.
Examples
# Examples
This code snippet fetch the list of users:
import (
miniflux "miniflux.app/client"
miniflux "miniflux.app/v2/client"
)
client := miniflux.New("https://api.example.org", "admin", "secret")
@@ -30,6 +28,5 @@ This one discover subscriptions on a website:
return
}
fmt.Println(subscriptions)
*/
package client // import "miniflux.app/client"
package client // import "miniflux.app/v2/client"
+50 -38
View File
@@ -1,8 +1,7 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package client // import "miniflux.app/client"
package client // import "miniflux.app/v2/client"
import (
"fmt"
@@ -18,24 +17,30 @@ const (
// User represents a user in the system.
type User struct {
ID int64 `json:"id"`
Username string `json:"username"`
Password string `json:"password,omitempty"`
IsAdmin bool `json:"is_admin"`
Theme string `json:"theme"`
Language string `json:"language"`
Timezone string `json:"timezone"`
EntryDirection string `json:"entry_sorting_direction"`
EntryOrder string `json:"entry_sorting_order"`
Stylesheet string `json:"stylesheet"`
GoogleID string `json:"google_id"`
OpenIDConnectID string `json:"openid_connect_id"`
EntriesPerPage int `json:"entries_per_page"`
KeyboardShortcuts bool `json:"keyboard_shortcuts"`
ShowReadingTime bool `json:"show_reading_time"`
EntrySwipe bool `json:"entry_swipe"`
LastLoginAt *time.Time `json:"last_login_at"`
DisplayMode string `json:"display_mode"`
ID int64 `json:"id"`
Username string `json:"username"`
Password string `json:"password,omitempty"`
IsAdmin bool `json:"is_admin"`
Theme string `json:"theme"`
Language string `json:"language"`
Timezone string `json:"timezone"`
EntryDirection string `json:"entry_sorting_direction"`
EntryOrder string `json:"entry_sorting_order"`
Stylesheet string `json:"stylesheet"`
GoogleID string `json:"google_id"`
OpenIDConnectID string `json:"openid_connect_id"`
EntriesPerPage int `json:"entries_per_page"`
KeyboardShortcuts bool `json:"keyboard_shortcuts"`
ShowReadingTime bool `json:"show_reading_time"`
EntrySwipe bool `json:"entry_swipe"`
GestureNav string `json:"gesture_nav"`
LastLoginAt *time.Time `json:"last_login_at"`
DisplayMode string `json:"display_mode"`
DefaultReadingSpeed int `json:"default_reading_speed"`
CJKReadingSpeed int `json:"cjk_reading_speed"`
DefaultHomePage string `json:"default_home_page"`
CategoriesSortingOrder string `json:"categories_sorting_order"`
MarkReadOnView bool `json:"mark_read_on_view"`
}
func (u User) String() string {
@@ -53,22 +58,28 @@ type UserCreationRequest struct {
// UserModificationRequest represents the request to update a user.
type UserModificationRequest struct {
Username *string `json:"username"`
Password *string `json:"password"`
IsAdmin *bool `json:"is_admin"`
Theme *string `json:"theme"`
Language *string `json:"language"`
Timezone *string `json:"timezone"`
EntryDirection *string `json:"entry_sorting_direction"`
EntryOrder *string `json:"entry_sorting_order"`
Stylesheet *string `json:"stylesheet"`
GoogleID *string `json:"google_id"`
OpenIDConnectID *string `json:"openid_connect_id"`
EntriesPerPage *int `json:"entries_per_page"`
KeyboardShortcuts *bool `json:"keyboard_shortcuts"`
ShowReadingTime *bool `json:"show_reading_time"`
EntrySwipe *bool `json:"entry_swipe"`
DisplayMode *string `json:"display_mode"`
Username *string `json:"username"`
Password *string `json:"password"`
IsAdmin *bool `json:"is_admin"`
Theme *string `json:"theme"`
Language *string `json:"language"`
Timezone *string `json:"timezone"`
EntryDirection *string `json:"entry_sorting_direction"`
EntryOrder *string `json:"entry_sorting_order"`
Stylesheet *string `json:"stylesheet"`
GoogleID *string `json:"google_id"`
OpenIDConnectID *string `json:"openid_connect_id"`
EntriesPerPage *int `json:"entries_per_page"`
KeyboardShortcuts *bool `json:"keyboard_shortcuts"`
ShowReadingTime *bool `json:"show_reading_time"`
EntrySwipe *bool `json:"entry_swipe"`
GestureNav *string `json:"gesture_nav"`
DisplayMode *string `json:"display_mode"`
DefaultReadingSpeed *int `json:"default_reading_speed"`
CJKReadingSpeed *int `json:"cjk_reading_speed"`
DefaultHomePage *string `json:"default_home_page"`
CategoriesSortingOrder *string `json:"categories_sorting_order"`
MarkReadOnView *bool `json:"mark_read_on_view"`
}
// Users represents a list of users.
@@ -208,6 +219,7 @@ type Entry struct {
ReadingTime int `json:"reading_time"`
Enclosures Enclosures `json:"enclosures,omitempty"`
Feed *Feed `json:"feed,omitempty"`
Tags []string `json:"tags"`
}
// Entries represents a list of entries.
+3 -4
View File
@@ -1,8 +1,7 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package client // import "miniflux.app/client"
package client // import "miniflux.app/v2/client"
import (
"bytes"
-8
View File
@@ -1,8 +0,0 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
package config // import "miniflux.app/config"
// Opts holds parsed configuration options.
var Opts *Options
-10
View File
@@ -1,10 +0,0 @@
// Copyright 2019 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
/*
Package config handles configuration management for the application.
*/
package config // import "miniflux.app/config"
+1 -2
View File
@@ -8,6 +8,5 @@ Here are few Docker Compose examples:
- `traefik.yml`: Use Traefik as reverse-proxy with automatic HTTPS
```bash
docker-compose -f basic.yml up -d db
docker-compose -f basic.yml up
docker compose -f basic.yml up -d
```
+3 -3
View File
@@ -1,4 +1,3 @@
version: '3.4'
services:
miniflux:
image: ${MINIFLUX_IMAGE:-miniflux/miniflux:latest}
@@ -7,7 +6,8 @@ services:
ports:
- "80:8080"
depends_on:
- db
db:
condition: service_healthy
environment:
- DATABASE_URL=postgres://miniflux:secret@db/miniflux?sslmode=disable
- RUN_MIGRATIONS=1
@@ -19,7 +19,7 @@ services:
# healthcheck:
# test: ["CMD", "/usr/bin/miniflux", "-healthcheck", "auto"]
db:
image: postgres:latest
image: postgres:15
container_name: postgres
environment:
- POSTGRES_USER=miniflux
+3 -3
View File
@@ -1,4 +1,3 @@
version: '3.4'
services:
caddy:
image: caddy:2
@@ -16,7 +15,8 @@ services:
image: ${MINIFLUX_IMAGE:-miniflux/miniflux:latest}
container_name: miniflux
depends_on:
- db
db:
condition: service_healthy
environment:
- DATABASE_URL=postgres://miniflux:secret@db/miniflux?sslmode=disable
- RUN_MIGRATIONS=1
@@ -25,7 +25,7 @@ services:
- ADMIN_PASSWORD=test123
- BASE_URL=https://miniflux.example.org
db:
image: postgres:latest
image: postgres:15
container_name: postgres
environment:
- POSTGRES_USER=miniflux
+3 -3
View File
@@ -1,4 +1,3 @@
version: '3.4'
services:
traefik:
image: "traefik:v2.3"
@@ -21,7 +20,8 @@ services:
image: ${MINIFLUX_IMAGE:-miniflux/miniflux:latest}
container_name: miniflux
depends_on:
- db
db:
condition: service_healthy
expose:
- "8080"
environment:
@@ -37,7 +37,7 @@ services:
- "traefik.http.routers.miniflux.entrypoints=websecure"
- "traefik.http.routers.miniflux.tls.certresolver=myresolver"
db:
image: postgres:latest
image: postgres:15
container_name: postgres
environment:
- POSTGRES_USER=miniflux
+31 -31
View File
@@ -20,7 +20,7 @@
"panels": [
{
"collapsed": false,
"datasource": null,
"datasource": "Prometheus",
"gridPos": {
"h": 1,
"w": 24,
@@ -104,7 +104,7 @@
"type": "bargauge"
},
{
"datasource": null,
"datasource": "Prometheus",
"fieldConfig": {
"defaults": {
"custom": {},
@@ -289,7 +289,7 @@
}
},
{
"datasource": null,
"datasource": "Prometheus",
"description": "",
"fieldConfig": {
"defaults": {
@@ -332,7 +332,7 @@
"pluginVersion": "7.1.5",
"targets": [
{
"expr": "go_memstats_sys_bytes{app=\"miniflux\"}",
"expr": "go_memstats_sys_bytes{job=\"miniflux\"}",
"interval": "",
"legendFormat": "{{ instance }} - Memory Used",
"refId": "A"
@@ -348,7 +348,7 @@
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": null,
"datasource": "Prometheus",
"fieldConfig": {
"defaults": {
"custom": {}
@@ -440,7 +440,7 @@
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": null,
"datasource": "Prometheus",
"fieldConfig": {
"defaults": {
"custom": {}
@@ -529,7 +529,7 @@
},
{
"collapsed": false,
"datasource": null,
"datasource": "Prometheus",
"gridPos": {
"h": 1,
"w": 24,
@@ -546,7 +546,7 @@
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": null,
"datasource": "Prometheus",
"fieldConfig": {
"defaults": {
"custom": {},
@@ -590,7 +590,7 @@
"steppedLine": false,
"targets": [
{
"expr": "go_memstats_sys_bytes{app=\"miniflux\"}",
"expr": "go_memstats_sys_bytes{job=\"miniflux\"}",
"format": "time_series",
"interval": "",
"intervalFactor": 1,
@@ -699,7 +699,7 @@
"steppedLine": false,
"targets": [
{
"expr": "process_open_fds{app=\"miniflux\"}",
"expr": "process_open_fds{job=\"miniflux\"}",
"interval": "",
"legendFormat": "{{instance }} - Open File Descriptors",
"refId": "A"
@@ -748,7 +748,7 @@
},
{
"collapsed": false,
"datasource": null,
"datasource": "Prometheus",
"gridPos": {
"h": 1,
"w": 24,
@@ -816,7 +816,7 @@
"steppedLine": false,
"targets": [
{
"expr": "go_memstats_alloc_bytes{app=\"miniflux\"}",
"expr": "go_memstats_alloc_bytes{job=\"miniflux\"}",
"format": "time_series",
"interval": "",
"intervalFactor": 2,
@@ -826,7 +826,7 @@
"step": 4
},
{
"expr": "rate(go_memstats_alloc_bytes_total{app=\"miniflux\"}[30s])",
"expr": "rate(go_memstats_alloc_bytes_total{job=\"miniflux\"}[30s])",
"format": "time_series",
"interval": "",
"intervalFactor": 2,
@@ -836,7 +836,7 @@
"step": 4
},
{
"expr": "go_memstats_stack_inuse_bytes{app=\"miniflux\"}",
"expr": "go_memstats_stack_inuse_bytes{job=\"miniflux\"}",
"format": "time_series",
"interval": "",
"intervalFactor": 2,
@@ -846,7 +846,7 @@
"step": 4
},
{
"expr": "go_memstats_heap_inuse_bytes{app=\"miniflux\"}",
"expr": "go_memstats_heap_inuse_bytes{job=\"miniflux\"}",
"format": "time_series",
"hide": false,
"interval": "",
@@ -904,7 +904,7 @@
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": null,
"datasource": "Prometheus",
"fieldConfig": {
"defaults": {
"custom": {}
@@ -945,13 +945,13 @@
"steppedLine": false,
"targets": [
{
"expr": "go_goroutines{app=\"miniflux\"}",
"expr": "go_goroutines{job=\"miniflux\"}",
"interval": "",
"legendFormat": "{{ instance }} - Goroutines",
"refId": "A"
},
{
"expr": "go_threads{app=\"miniflux\"}",
"expr": "go_threads{job=\"miniflux\"}",
"interval": "",
"legendFormat": "{{ instance }} - OS threads",
"refId": "B"
@@ -1003,7 +1003,7 @@
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": null,
"datasource": "Prometheus",
"fieldConfig": {
"defaults": {
"custom": {},
@@ -1046,7 +1046,7 @@
"steppedLine": false,
"targets": [
{
"expr": "go_memstats_stack_inuse_bytes{app=\"miniflux\"}",
"expr": "go_memstats_stack_inuse_bytes{job=\"miniflux\"}",
"format": "time_series",
"interval": "",
"intervalFactor": 1,
@@ -1054,7 +1054,7 @@
"refId": "A"
},
{
"expr": "go_memstats_stack_sys_bytes{app=\"miniflux\"}",
"expr": "go_memstats_stack_sys_bytes{job=\"miniflux\"}",
"format": "time_series",
"interval": "",
"intervalFactor": 1,
@@ -1108,7 +1108,7 @@
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": null,
"datasource": "Prometheus",
"fieldConfig": {
"defaults": {
"custom": {},
@@ -1150,7 +1150,7 @@
"steppedLine": false,
"targets": [
{
"expr": "go_memstats_heap_alloc_bytes{app=\"miniflux\"}",
"expr": "go_memstats_heap_alloc_bytes{job=\"miniflux\"}",
"format": "time_series",
"interval": "",
"intervalFactor": 1,
@@ -1158,7 +1158,7 @@
"refId": "B"
},
{
"expr": "go_memstats_heap_sys_bytes{app=\"miniflux\"}",
"expr": "go_memstats_heap_sys_bytes{job=\"miniflux\"}",
"format": "time_series",
"interval": "",
"intervalFactor": 1,
@@ -1166,7 +1166,7 @@
"refId": "A"
},
{
"expr": "go_memstats_heap_idle_bytes{app=\"miniflux\"}",
"expr": "go_memstats_heap_idle_bytes{job=\"miniflux\"}",
"format": "time_series",
"interval": "",
"intervalFactor": 1,
@@ -1174,7 +1174,7 @@
"refId": "C"
},
{
"expr": "go_memstats_heap_inuse_bytes{app=\"miniflux\"}",
"expr": "go_memstats_heap_inuse_bytes{job=\"miniflux\"}",
"format": "time_series",
"interval": "",
"intervalFactor": 1,
@@ -1182,7 +1182,7 @@
"refId": "D"
},
{
"expr": "go_memstats_heap_released_bytes{app=\"miniflux\"}",
"expr": "go_memstats_heap_released_bytes{job=\"miniflux\"}",
"format": "time_series",
"interval": "",
"intervalFactor": 1,
@@ -1282,7 +1282,7 @@
"steppedLine": false,
"targets": [
{
"expr": "go_gc_duration_seconds{app=\"miniflux\"}",
"expr": "go_gc_duration_seconds{job=\"miniflux\"}",
"format": "time_series",
"interval": "",
"intervalFactor": 2,
@@ -1339,7 +1339,7 @@
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": null,
"datasource": "Prometheus",
"fieldConfig": {
"defaults": {
"custom": {},
@@ -1383,7 +1383,7 @@
"steppedLine": false,
"targets": [
{
"expr": "go_memstats_mallocs_total{app=\"miniflux\"} - go_memstats_frees_total{app=\"miniflux\"}",
"expr": "go_memstats_mallocs_total{job=\"miniflux\"} - go_memstats_frees_total{job=\"miniflux\"}",
"format": "time_series",
"interval": "",
"intervalFactor": 1,
@@ -1462,4 +1462,4 @@
"title": "Miniflux",
"uid": "vSaPgcFMk",
"version": 23
}
}
+7
View File
@@ -0,0 +1,7 @@
System-V init for e.g. http://devuan.org
Assumes an executable `/usr/local/bin/miniflux`.
Configure in `etc/default/miniflux`
+6
View File
@@ -0,0 +1,6 @@
# sourced by /etc/init.d/miniflux
# see cluster port in pg_lsclusters and ls -Al /var/run/postgresql/
export DATABASE_URL='host=/var/run/postgresql/ port=5433 user=miniflux password=<my secrect db password> dbname=miniflux sslmode=disable'
export LISTEN_ADDR='127.0.0.1:8081'
export BASE_URL='https://<my miniflux domain> and path/'
+127
View File
@@ -0,0 +1,127 @@
#! /bin/sh
### BEGIN INIT INFO
# Provides: miniflux
# Required-Start: $syslog $network
# Required-Stop: $syslog
# Should-Start: postgresql
# Should-Stop: postgresql
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: A rss reader
# Description: A RSS reader
### END INIT INFO
# Author: Danny Boisvert
# Do NOT "set -e"
# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="Miniflux"
NAME=miniflux
SERVICEVERBOSE=yes
PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME
WORKINGDIR=/usr/local/bin
DAEMON=$WORKINGDIR/$NAME
DAEMON_ARGS=""
USER=nobody
# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME
# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0
# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh
# Define LSB log_* functions.
# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
# and status_of_proc is working.
. /lib/lsb/init-functions
#
# Function that starts the daemon/service
#
do_start()
{
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
sh -c "USER=$USER start-stop-daemon --start --quiet --pidfile $PIDFILE --make-pidfile \\
--test --chdir $WORKINGDIR --chuid $USER \\
--exec $DAEMON -- $DAEMON_ARGS > /dev/null \\
|| return 1"
sh -c "USER=$USER start-stop-daemon --start --quiet --pidfile $PIDFILE --make-pidfile \\
--background --chdir $WORKINGDIR --chuid $USER \\
--exec $DAEMON -- $DAEMON_ARGS \\
|| return 2"
}
#
# Function that stops the daemon/service
#
do_stop()
{
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
start-stop-daemon --stop --quiet --retry=TERM/1/KILL/5 --pidfile $PIDFILE --name $NAME
RETVAL="$?"
[ "$RETVAL" = 2 ] && return 2
start-stop-daemon --stop --quiet --oknodo --retry=0/1/KILL/5 --exec $DAEMON
[ "$?" = 2 ] && return 2
# Many daemons don't delete their pidfiles when they exit.
rm -f $PIDFILE
return "$RETVAL"
}
case "$1" in
start)
[ "$SERVICEVERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
do_start
case "$?" in
0|1) [ "$SERVICEVERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$SERVICEVERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "$SERVICEVERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
case "$?" in
0|1) [ "$SERVICEVERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$SERVICEVERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
status)
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
;;
restart|force-reload)
log_daemon_msg "Restarting $DESC" "$NAME"
do_stop
case "$?" in
0|1)
do_start
case "$?" in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
exit 3
;;
esac
+6
View File
@@ -0,0 +1,6 @@
Miniflux API Collection for Thunder Client VS Code Extension
============================================================
Official website: https://www.thunderclient.com
This folder contains the API endpoints collection for Miniflux. You can import it locally to interact with the Miniflux API.
+769
View File
@@ -0,0 +1,769 @@
{
"client": "Thunder Client",
"collectionName": "Miniflux v2",
"dateExported": "2023-07-31T01:53:38.743Z",
"version": "1.1",
"folders": [],
"requests": [
{
"_id": "d23fb9ba-c0c1-46ff-93f4-c5ed24ecd56e",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Discover Subscriptions",
"url": "/v1/discover",
"method": "POST",
"sortNum": 20000,
"created": "2023-07-31T01:20:12.275Z",
"modified": "2023-07-31T01:29:39.751Z",
"headers": [],
"params": [],
"body": {
"type": "json",
"raw": "\n{\n \"url\": \"https://miniflux.app/\"\n}",
"form": []
},
"tests": []
},
{
"_id": "29cfc679-31d4-4d8c-b843-ab92a74dfa85",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Get Feeds",
"url": "/v1/feeds",
"method": "GET",
"sortNum": 50000,
"created": "2023-07-31T01:20:12.276Z",
"modified": "2023-07-31T01:20:12.276Z",
"headers": [],
"params": [],
"tests": []
},
{
"_id": "52a88df8-41c7-47c2-a635-8c93d7d29f40",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Get Category Feeds",
"url": "/v1/categories/1/feeds",
"method": "GET",
"sortNum": 60000,
"created": "2023-07-31T01:20:12.277Z",
"modified": "2023-07-31T01:20:12.277Z",
"headers": [],
"params": [],
"tests": []
},
{
"_id": "a5c2cb48-a4cf-4edc-a0e0-927d9f711843",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Get Feed",
"url": "/v1/feeds/{feedID}",
"method": "GET",
"sortNum": 70000,
"created": "2023-07-31T01:20:12.279Z",
"modified": "2023-07-31T01:31:11.478Z",
"headers": [],
"params": [
{
"name": "feedID",
"value": "1",
"isPath": true
}
],
"tests": []
},
{
"_id": "fb55b058-c2ba-4785-be92-a98f0596e86e",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Get Feed Icon ",
"url": "/v1/feeds/{feedID}/icon",
"method": "GET",
"sortNum": 80000,
"created": "2023-07-31T01:20:12.280Z",
"modified": "2023-07-31T01:31:18.174Z",
"headers": [],
"params": [
{
"name": "feedID",
"value": "1",
"isPath": true
}
],
"tests": []
},
{
"_id": "c0ec9a45-263e-4627-a13b-b5df901a6456",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Create Feed ",
"url": "/v1/feeds",
"method": "POST",
"sortNum": 90000,
"created": "2023-07-31T01:20:12.281Z",
"modified": "2023-07-31T01:31:31.415Z",
"headers": [],
"params": [],
"body": {
"type": "json",
"raw": "{\n \"feed_url\": \"https://miniflux.app/feed.xml\",\n \"category_id\": 1\n}",
"form": []
},
"tests": []
},
{
"_id": "f4c078a2-c031-4753-a7a4-4987439a61d0",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Update Feed",
"url": "/v1/feeds/{feedID}",
"method": "PUT",
"sortNum": 100000,
"created": "2023-07-31T01:20:12.282Z",
"modified": "2023-07-31T01:31:48.115Z",
"headers": [],
"params": [
{
"name": "feedID",
"value": "1",
"isPath": true
}
],
"body": {
"type": "json",
"raw": "{\n \"title\": \"Updated - New Feed Title\",\n \"category_id\": 1\n}",
"form": []
},
"tests": []
},
{
"_id": "1e47aeab-09ce-439b-907f-f9347b98b160",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Refresh Feed",
"url": "/v1/feeds/{feedID}/refresh",
"method": "PUT",
"sortNum": 110000,
"created": "2023-07-31T01:20:12.283Z",
"modified": "2023-07-31T01:31:58.778Z",
"headers": [],
"params": [
{
"name": "feedID",
"value": "1",
"isPath": true
}
],
"tests": []
},
{
"_id": "4f643fa6-042d-4e95-8194-4cb0af7102bf",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Refresh All Feeds",
"url": "/v1/feeds/refresh",
"method": "PUT",
"sortNum": 115000,
"created": "2023-07-31T01:20:12.312Z",
"modified": "2023-07-31T01:20:12.312Z",
"headers": [],
"params": [],
"tests": []
},
{
"_id": "d829f651-e9b9-41f9-aa9e-bd830d5e6389",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Remove Feed",
"url": "/v1/feeds/{feedID}",
"method": "DELETE",
"sortNum": 120000,
"created": "2023-07-31T01:20:12.284Z",
"modified": "2023-07-31T01:32:16.723Z",
"headers": [],
"params": [
{
"name": "feedID",
"value": "1",
"isPath": true
}
],
"tests": []
},
{
"_id": "deafbf1a-d9e0-420f-a749-1bdde56772cb",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Get Feed Entries",
"url": "/v1/feeds/{feedID}/entries",
"method": "GET",
"sortNum": 130000,
"created": "2023-07-31T01:20:12.285Z",
"modified": "2023-07-31T01:32:52.812Z",
"headers": [],
"params": [
{
"name": "feedID",
"value": "2",
"isPath": true
}
],
"tests": []
},
{
"_id": "0052e903-75fc-48ec-8fd5-6e8784ed401a",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Get Entry",
"url": "/v1/entries/{entryID}",
"method": "GET",
"sortNum": 140000,
"created": "2023-07-31T01:20:12.286Z",
"modified": "2023-07-31T01:33:30.417Z",
"headers": [],
"params": [
{
"name": "entryID",
"value": "19",
"isPath": true
}
],
"tests": []
},
{
"_id": "1a055ace-2629-4298-9ea0-1bd17d59a4d6",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Fetch original article",
"url": "/v1/entries/{entryID}/fetch-content",
"method": "GET",
"sortNum": 150000,
"created": "2023-07-31T01:20:12.287Z",
"modified": "2023-07-31T01:33:41.014Z",
"headers": [],
"params": [
{
"name": "entryID",
"value": "19",
"isPath": true
}
],
"tests": []
},
{
"_id": "f272d1e6-ebbb-4c58-a159-4412ad657136",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Get Category Entries",
"url": "/v1/categories/{categoryID}/entries",
"method": "GET",
"sortNum": 160000,
"created": "2023-07-31T01:20:12.288Z",
"modified": "2023-07-31T01:20:12.288Z",
"headers": [],
"params": [
{
"name": "categoryID",
"value": "1",
"isPath": true
}
],
"tests": []
},
{
"_id": "856ed091-318a-4a76-b7ce-6475106dd6b5",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Mark All Feed Entries as Read",
"url": "/v1/feeds/{feedID}/mark-all-as-read",
"method": "PUT",
"sortNum": 180000,
"created": "2023-07-31T01:20:12.290Z",
"modified": "2023-07-31T01:46:57.443Z",
"headers": [],
"params": [
{
"name": "feedID",
"value": "2",
"isPath": true
}
],
"tests": []
},
{
"_id": "67749962-d646-45d5-8b78-a8eeaa7cb971",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Get Entries",
"url": "/v1/entries",
"method": "GET",
"sortNum": 190000,
"created": "2023-07-31T01:20:12.291Z",
"modified": "2023-07-31T01:20:12.291Z",
"headers": [],
"params": [],
"tests": []
},
{
"_id": "b55ae165-2abe-41f0-8b8a-14d826238d20",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Change Entries Status",
"url": "/v1/entries",
"method": "PUT",
"sortNum": 200000,
"created": "2023-07-31T01:20:12.292Z",
"modified": "2023-07-31T01:46:46.133Z",
"headers": [],
"params": [],
"body": {
"type": "json",
"raw": "{\n \"entry_ids\": [19, 20],\n \"status\": \"read\"\n}",
"form": []
},
"tests": []
},
{
"_id": "710dfc55-fc4e-48ab-989e-3ed78019d6c3",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Toggle Entry Bookmark",
"url": "/v1/entries/{entryID}/bookmark",
"method": "PUT",
"sortNum": 210000,
"created": "2023-07-31T01:20:12.293Z",
"modified": "2023-07-31T01:45:51.933Z",
"headers": [],
"params": [
{
"name": "entryID",
"value": "19",
"isPath": true
}
],
"tests": []
},
{
"_id": "19edbe55-0a0a-4102-bde0-73ed6d8515f6",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Save Entry to Third-Party Service",
"url": "/v1/entries/{entryID}/save",
"method": "POST",
"sortNum": 215000,
"created": "2023-07-31T01:20:12.313Z",
"modified": "2023-07-31T01:20:12.313Z",
"headers": [],
"params": [
{
"name": "entryID",
"value": "1",
"isPath": true
}
],
"tests": []
},
{
"_id": "13d2cf52-aa08-4f7f-a83d-ffcb1e1190cd",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Get Categories",
"url": "/v1/categories",
"method": "GET",
"sortNum": 220000,
"created": "2023-07-31T01:20:12.294Z",
"modified": "2023-07-31T01:20:12.294Z",
"headers": [],
"params": [],
"tests": []
},
{
"_id": "1547dabe-2bcb-4e06-acaa-fb393d1027e2",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Create Category ",
"url": "/v1/categories",
"method": "POST",
"sortNum": 230000,
"created": "2023-07-31T01:20:12.295Z",
"modified": "2023-07-31T01:20:12.295Z",
"headers": [],
"params": [],
"body": {
"type": "json",
"raw": "{\n \"title\": \"My category\"\n}",
"form": []
},
"tests": []
},
{
"_id": "e8dac503-19dc-434d-832f-eac4364785d8",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Update Category",
"url": "/v1/categories/{categoryID}",
"method": "PUT",
"sortNum": 232500,
"created": "2023-07-31T01:20:12.296Z",
"modified": "2023-07-31T01:42:55.831Z",
"headers": [],
"params": [
{
"name": "categoryID",
"value": "3",
"isPath": true
}
],
"body": {
"type": "json",
"raw": "\n{\n \"title\": \"My new title\"\n}",
"form": []
},
"tests": []
},
{
"_id": "86d74247-7f12-4a6e-91b3-fad9e7b6b1fb",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Delete Category",
"url": "/v1/categories/{categoryID}",
"method": "DELETE",
"sortNum": 235000,
"created": "2023-07-31T01:20:12.298Z",
"modified": "2023-07-31T01:44:21.486Z",
"headers": [],
"params": [
{
"name": "categoryID",
"value": "3",
"isPath": true
}
],
"tests": []
},
{
"_id": "668dde80-ed03-4fa6-ad2a-9cacd0ec31eb",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Mark Category Entries as Read",
"url": "/v1/categories/{categoryID}/mark-all-as-read",
"method": "PUT",
"sortNum": 237500,
"created": "2023-07-31T01:20:12.299Z",
"modified": "2023-07-31T01:43:50.637Z",
"headers": [],
"params": [
{
"name": "categoryID",
"value": "1",
"isPath": true
}
],
"tests": []
},
{
"_id": "39ada469-765e-4584-ab00-9d263bd526a1",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Get Category Feeds",
"url": "/v1/categories/{categoryID}/feeds",
"method": "GET",
"sortNum": 243750,
"created": "2023-07-31T01:50:23.959Z",
"modified": "2023-07-31T01:50:51.443Z",
"headers": [],
"params": [
{
"name": "categoryID",
"value": "1",
"isPath": true
}
],
"tests": []
},
{
"_id": "ec389c41-185f-4b57-a373-c6ff952b4282",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Refresh Category Feeds",
"url": "/v1/categories/{categoryID}/refresh",
"method": "PUT",
"sortNum": 250000,
"created": "2023-07-31T01:20:12.297Z",
"modified": "2023-07-31T01:43:23.102Z",
"headers": [],
"params": [
{
"name": "categoryID",
"value": "1",
"isPath": true
}
],
"tests": []
},
{
"_id": "bc4a7578-c95e-4436-bbfa-61ccc4a8fc71",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Get Category Entries",
"url": "/v1/categories/{categoryID}/entries",
"method": "GET",
"sortNum": 257500,
"created": "2023-07-31T01:51:15.403Z",
"modified": "2023-07-31T01:51:35.106Z",
"headers": [],
"params": [
{
"name": "categoryID",
"value": "1",
"isPath": true
}
],
"tests": []
},
{
"_id": "fa935fb3-3ed6-4ee3-b995-6c054766d109",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Get Category Entry",
"url": "/v1/categories/{categoryID}/entries/{entryID}",
"method": "GET",
"sortNum": 258750,
"created": "2023-07-31T01:51:46.699Z",
"modified": "2023-07-31T01:52:12.155Z",
"headers": [],
"params": [
{
"name": "categoryID",
"value": "1",
"isPath": true
},
{
"name": "entryID",
"value": "19",
"isPath": true
}
],
"tests": []
},
{
"_id": "cb6968e9-8d13-4410-9ad5-85847b73d7eb",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "OPML Export",
"url": "/v1/export",
"method": "GET",
"sortNum": 280000,
"created": "2023-07-31T01:20:12.300Z",
"modified": "2023-07-31T01:20:12.300Z",
"headers": [],
"params": [],
"tests": []
},
{
"_id": "169a64e1-08dd-4760-b405-a748a5286b38",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "OPML Import",
"url": "/v1/import",
"method": "POST",
"sortNum": 290000,
"created": "2023-07-31T01:20:12.301Z",
"modified": "2023-07-31T01:41:31.218Z",
"headers": [],
"params": [],
"body": {
"type": "xml",
"raw": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<opml version=\"2.0\">\n <head>\n <title>Miniflux</title>\n <dateCreated>Sun, 30 Jul 2023 18:41:08 PDT</dateCreated>\n </head>\n <body>\n <outline text=\"All\">\n <outline title=\"Miniflux\" text=\"Miniflux\" xmlUrl=\"https://miniflux.app/feed.xml\" htmlUrl=\"https://miniflux.app\"></outline>\n </outline>\n </body>\n</opml>",
"form": []
},
"tests": []
},
{
"_id": "bfb7264a-7b46-49fe-b451-fb6d9b03f0b2",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Create User",
"url": "/v1/users",
"method": "POST",
"sortNum": 300000,
"created": "2023-07-31T01:20:12.302Z",
"modified": "2023-07-31T01:20:12.302Z",
"headers": [],
"params": [],
"body": {
"type": "json",
"raw": "{\n \"username\": \"bob\",\n \"password\": \"test123\",\n \"is_admin\": false\n}",
"form": []
},
"tests": []
},
{
"_id": "93c1dcc2-bf09-4e8e-86ba-0c042147a48f",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Update User",
"url": "/v1/users/{userID}",
"method": "PUT",
"sortNum": 310000,
"created": "2023-07-31T01:20:12.303Z",
"modified": "2023-07-31T01:40:09.576Z",
"headers": [],
"params": [
{
"name": "userID",
"value": "2",
"isPath": true
}
],
"body": {
"type": "json",
"raw": "{\n \"username\": \"joe\"\n}",
"form": []
},
"tests": []
},
{
"_id": "19cf34c1-eb0a-4442-a682-2e94c4f5e594",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Get Current User",
"url": "/v1/me",
"method": "GET",
"sortNum": 320000,
"created": "2023-07-31T01:20:12.304Z",
"modified": "2023-07-31T01:20:12.304Z",
"headers": [],
"params": [],
"tests": []
},
{
"_id": "4a700f7c-8762-4cab-aab1-2d8066884d69",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Get User by ID",
"url": "/v1/users/{userID}",
"method": "GET",
"sortNum": 330000,
"created": "2023-07-31T01:20:12.305Z",
"modified": "2023-07-31T01:39:38.472Z",
"headers": [],
"params": [
{
"name": "userID",
"value": "1",
"isPath": true
}
],
"tests": []
},
{
"_id": "66cb0985-5ed4-4b1e-9029-8605b7f5f74e",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Get User by username",
"url": "/v1/users/{username}",
"method": "GET",
"sortNum": 335000,
"created": "2023-07-31T01:47:53.649Z",
"modified": "2023-07-31T01:48:10.655Z",
"headers": [],
"params": [
{
"name": "username",
"value": "admin",
"isPath": true
}
],
"tests": []
},
{
"_id": "3d4b227a-83a2-4d87-a0ed-ce9d5497aea6",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Get Users",
"url": "/v1/users",
"method": "GET",
"sortNum": 340000,
"created": "2023-07-31T01:20:12.306Z",
"modified": "2023-07-31T01:20:12.306Z",
"headers": [],
"params": [],
"tests": []
},
{
"_id": "90138dea-799a-4b44-ad68-fce6ec5898a6",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Delete User",
"url": "/v1/users/{userID}",
"method": "DELETE",
"sortNum": 350000,
"created": "2023-07-31T01:20:12.307Z",
"modified": "2023-07-31T01:40:38.124Z",
"headers": [],
"params": [
{
"name": "userID",
"value": "2",
"isPath": true
}
],
"tests": []
},
{
"_id": "4b3bf7ca-bc55-423b-a3ee-6279c10a0d85",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Fetch Read/Unread Counters",
"url": "/v1/feeds/counters",
"method": "GET",
"sortNum": 370000,
"created": "2023-07-31T01:20:12.309Z",
"modified": "2023-07-31T01:20:12.309Z",
"headers": [],
"params": [],
"tests": []
},
{
"_id": "7721682f-31e3-4d71-8df9-02e30e4729d7",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Healthcheck",
"url": "/healthcheck",
"method": "GET",
"sortNum": 380000,
"created": "2023-07-31T01:20:12.310Z",
"modified": "2023-07-31T01:20:12.310Z",
"headers": [],
"params": [],
"tests": []
},
{
"_id": "64410254-b17a-43e4-984d-10b9b13c5818",
"colId": "fc35618a-f39f-40a0-a443-d4ae568baa8e",
"containerId": "",
"name": "Version",
"url": "/version",
"method": "GET",
"sortNum": 390000,
"created": "2023-07-31T01:20:12.311Z",
"modified": "2023-07-31T01:20:12.311Z",
"headers": [],
"params": [],
"tests": []
}
],
"settings": {
"auth": {
"type": "basic",
"basic": {
"username": "admin",
"password": "test123"
}
},
"options": {
"baseUrl": "http://localhost:8080"
}
}
}
-10
View File
@@ -1,10 +0,0 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
/*
Package crypto implements helpers related to cryptography.
*/
package crypto // import "miniflux.app/crypto"
-10
View File
@@ -1,10 +0,0 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
/*
Miniflux is a feed reader application.
*/
package main // import "miniflux.app"
-10
View File
@@ -1,10 +0,0 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
/*
Package errors handles localized errors.
*/
package errors // import "miniflux.app/errors"
-10
View File
@@ -1,10 +0,0 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
/*
Package fever implements Fever API endpoints.
*/
package fever // import "miniflux.app/fever"
+35 -20
View File
@@ -1,27 +1,42 @@
module miniflux.app
module miniflux.app/v2
// +heroku goVersion go1.16
// +heroku goVersion go1.21
require (
github.com/PuerkitoBio/goquery v1.8.0
github.com/coreos/go-oidc v2.2.1+incompatible
github.com/felixge/httpsnoop v1.0.1 // indirect
github.com/PuerkitoBio/goquery v1.8.1
github.com/coreos/go-oidc/v3 v3.6.0
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible
github.com/golang/gddo v0.0.0-20200831202555-721e228c7686 // indirect
github.com/gorilla/mux v1.8.0
github.com/lib/pq v1.10.6
github.com/mitchellh/go-server-timing v1.0.2-0.20201108055052-feb680ab92c2
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
github.com/prometheus/client_golang v1.12.2
github.com/rylans/getlang v0.0.0-20200505200108-4c3188ff8a2d
github.com/stretchr/testify v1.6.1 // indirect
github.com/tdewolff/minify/v2 v2.11.5
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c
gopkg.in/square/go-jose.v2 v2.5.0 // indirect
mvdan.cc/xurls/v2 v2.4.0
github.com/lib/pq v1.10.9
github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530
github.com/mccutchen/go-httpbin/v2 v2.11.0
github.com/prometheus/client_golang v1.16.0
github.com/rylans/getlang v0.0.0-20201227074721-9e7f44ff8aa0
github.com/tdewolff/minify/v2 v2.12.8
github.com/yuin/goldmark v1.5.6
golang.org/x/crypto v0.12.0
golang.org/x/net v0.14.0
golang.org/x/oauth2 v0.11.0
golang.org/x/term v0.11.0
mvdan.cc/xurls/v2 v2.5.0
)
go 1.16
require (
github.com/andybalholm/cascadia v1.3.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/go-jose/go-jose/v3 v3.0.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.42.0 // indirect
github.com/prometheus/procfs v0.10.1 // indirect
github.com/tdewolff/parse/v2 v2.6.7 // indirect
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
golang.org/x/sys v0.11.0 // indirect
golang.org/x/text v0.12.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.31.0 // indirect
)
go 1.21
+77 -593
View File
@@ -1,640 +1,124 @@
cloud.google.com/go v0.16.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/PuerkitoBio/goquery v1.8.0 h1:PJTF7AmFCFKk1N6V6jmKfrNH9tV5pNE6lZMkG0gta/U=
github.com/PuerkitoBio/goquery v1.8.0/go.mod h1:ypIiRMtY7COPGk+I/YbZLbxsxn9g5ejnI2HSMtkjZvI=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM=
github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ=
github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c=
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bradfitz/gomemcache v0.0.0-20170208213004-1952afaa557d/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-oidc v2.2.1+incompatible h1:mh48q/BqXqgjVHpy2ZY7WnWAbenxRjsz9N1i1YxjHAk=
github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cosiner/argv v0.1.0/go.mod h1:EusR6TucWKX+zFgtdUsKT2Cvg45K5rtpCcWz4hK06d8=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/coreos/go-oidc/v3 v3.6.0 h1:AKVxfYw1Gmkn/w96z0DbT/B/xFnzTd3MkZvWLjF4n/o=
github.com/coreos/go-oidc/v3 v3.6.0/go.mod h1:ZpHUsHBucTUj6WOkrP4E20UPynbLZzhTQ1XKCXkxyPc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/djherbis/atime v1.1.0/go.mod h1:28OF6Y8s3NQWwacXc5eZTsEsiMzp7LF8MbXE+XJPdBE=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/felixge/httpsnoop v1.0.0/go.mod h1:3+D9sFq0ahK/JeJPhCBUV1xlf4/eIYrUQaxulT0VzX8=
github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fsnotify/fsnotify v1.4.3-0.20170329110642-4da3e2cfbabc/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.5.3/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
github.com/garyburd/redigo v1.1.1-0.20170914051019-70e1b1943d4f/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-delve/delve v1.5.0/go.mod h1:c6b3a1Gry6x8a4LGCe/CWzrocrfaHvkUxCj3k4bvSUQ=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-stack/stack v1.6.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo=
github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8=
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible h1:2cauKuaELYAEARXRkq2LrJ0yDDv1rW7+wrTEdVL3uaU=
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang/gddo v0.0.0-20180823221919-9d8ff1c67be5/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4=
github.com/golang/gddo v0.0.0-20200831202555-721e228c7686 h1:5vu7C+63KTbsSNnLhrgB98Sqy8MNVSW8FdhkcWA/3Rk=
github.com/golang/gddo v0.0.0-20200831202555-721e228c7686/go.mod h1:sam69Hju0uq+5uvLJUMDlsKlQ21Vrs1Kd/1YFPNYdOU=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/lint v0.0.0-20170918230701-e5d664eb928e/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.1.1-0.20171103154506-982329095285/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-dap v0.2.0/go.mod h1:5q8aYQFnHOAZEMP+6vmq25HKYAEwE+LF5yh7JKrrhSQ=
github.com/google/go-dap v0.3.0/go.mod h1:5q8aYQFnHOAZEMP+6vmq25HKYAEwE+LF5yh7JKrrhSQ=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gregjones/httpcache v0.0.0-20170920190843-316c5e0ff04e/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/hcl v0.0.0-20170914154624-68e816d1c783/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/log15 v0.0.0-20170622235902-74a0988b5f80/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs=
github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/magiconair/properties v1.7.4-0.20170902060319-8d7837e64d3c/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2/go.mod h1:0KeJpeMD6o+O4hW7qJOT7vyQPKrWmj26uf5wMc/IiIs=
github.com/mattn/go-colorable v0.0.0-20170327083344-ded68f7a9561/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.0.10-0.20170816031813-ad5389df28cd/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.2/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-server-timing v1.0.2-0.20201108055052-feb680ab92c2 h1:9kYRAm87/M5VL+HWegDGIorBWDiErrZrksLKTJBF2IQ=
github.com/mitchellh/go-server-timing v1.0.2-0.20201108055052-feb680ab92c2/go.mod h1:8mKJVJkyMI20ifXXO0zlV3sh3FrtjvltAeBqz38clBE=
github.com/mitchellh/mapstructure v0.0.0-20170523030023-d0303fe80992/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/pelletier/go-toml v1.0.1-0.20170904195809-1d6b12b7cb29/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/peterh/liner v0.0.0-20170317030525-88609521dc4b/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
github.com/peterh/liner v1.2.0/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530 h1:kHKxCOLcHH8r4Fzarl4+Y3K5hjothkVW5z7T1dUM11U=
github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/mccutchen/go-httpbin/v2 v2.11.0 h1:uDVmzefIbcG9NeEmWxwy7PdxztY+oCRlOLbHSaXdSF4=
github.com/mccutchen/go-httpbin/v2 v2.11.0/go.mod h1:f4DUXYlU6yH0V81O4lJIwqpmYdTXXmYwzxMnYEimFPk=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 h1:J9b7z+QKAmPf4YLrFg6oQUotqHQeUNWwkvo7jZp1GLU=
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34=
github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/rylans/getlang v0.0.0-20200505200108-4c3188ff8a2d h1:4Jn2kzSKcpxxwpJdyWxfNWKCYe4Uki2VibkExYmBLiA=
github.com/rylans/getlang v0.0.0-20200505200108-4c3188ff8a2d/go.mod h1:3vfmZI6aJd5Rb9W2TQ0Nmupl+qem21R05+hmCscI0Bk=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v0.0.0-20170901052352-ee1bd8ee15a1/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.1.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.0-20170417170307-b6cb39589372/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
github.com/spf13/jwalterweatherman v0.0.0-20170901151539-12bd96e66386/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v0.0.0-20170417173400-9e4c21054fa1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.1-0.20170901120850-7aff26db30c1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM=
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg=
github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
github.com/rylans/getlang v0.0.0-20201227074721-9e7f44ff8aa0 h1:qSaU9YAEIxk/ozcmY1hiauktAYTpbwYIrPdQ0L2E8UM=
github.com/rylans/getlang v0.0.0-20201227074721-9e7f44ff8aa0/go.mod h1:3vfmZI6aJd5Rb9W2TQ0Nmupl+qem21R05+hmCscI0Bk=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/tdewolff/minify/v2 v2.11.5 h1:wfRJ6JMmu87Azx+Lj7NcCTg8D/L/92SNuYF5fv31fjg=
github.com/tdewolff/minify/v2 v2.11.5/go.mod h1:ZR6VK7tbgF0XXBVwDHXrbqM4tGYchBpdwhsbKeDmAww=
github.com/tdewolff/parse/v2 v2.5.31 h1:PrJN/trWTUYaYxg7jRpKnKXpBK4kBjT9rAFhFAh2Lus=
github.com/tdewolff/parse/v2 v2.5.31/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho=
github.com/tdewolff/test v1.0.6 h1:76mzYJQ83Op284kMT+63iCNCI7NEERsIN8dLM+RiKr4=
github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/tdewolff/minify/v2 v2.12.8 h1:Q2BqOTmlMjoutkuD/OPCnJUpIqrzT3nRPkw+q+KpXS0=
github.com/tdewolff/minify/v2 v2.12.8/go.mod h1:YRgk7CC21LZnbuke2fmYnCTq+zhCgpb0yJACOTUNJ1E=
github.com/tdewolff/parse/v2 v2.6.7 h1:WrFllrqmzAcrKHzoYgMupqgUBIfBVOb0yscFzDf8bBg=
github.com/tdewolff/parse/v2 v2.6.7/go.mod h1:XHDhaU6IBgsryfdnpzUXBlT6leW/l25yrFBTEb4eIyM=
github.com/tdewolff/test v1.0.9 h1:SswqJCmeN4B+9gEAi/5uqT0qpi1y2/2O47V/1hhGZT0=
github.com/tdewolff/test v1.0.9/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.starlark.net v0.0.0-20190702223751-32f345186213/go.mod h1:c1/X6cHgvdXj6pUlmWKMkuqRnW4K8x2vwt6JAaaircg=
go.starlark.net v0.0.0-20201006213952-227f4aabceb5/go.mod h1:f0znQkUKRrkk36XxWbGjMqQM8wGv/xHBVE2qc3B5oFU=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/arch v0.0.0-20190927153633-4e8777c89be4/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4=
golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark v1.5.6 h1:COmQAWTCcGetChm3Ig7G/t8AFAN00t+o8Mt4cf7JpwA=
github.com/yuin/goldmark v1.5.6/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8 h1:/6y1LfuqNuQdHAm0jjtPtgRcxIxjVZgm5OTu8/QhZvk=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20170912212905-13449ad91cb2/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c h1:pkQiBZBvdos9qq4wBAHqlzuZHEXo07pqV06ef90u1WI=
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/sync v0.0.0-20170517211232-f52d1811a629/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU=
golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0=
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20170424234030-8be79e1e0910/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191127201027-ecd32218bd7f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.0.0-20170921000349-586095a6e407/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20170918111702-1e559d0a00ee/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/grpc v1.2.1-0.20170921194603-d4b75ebd4f9f/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/square/go-jose.v2 v2.5.0 h1:OZ4sdq+Y+SHfYB7vfthi1Ei8b0vkP8ZPQgUfUwdUSqo=
gopkg.in/square/go-jose.v2 v2.5.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
mvdan.cc/xurls/v2 v2.4.0 h1:tzxjVAj+wSBmDcF6zBB7/myTy3gX9xvi8Tyr28AuQgc=
mvdan.cc/xurls/v2 v2.4.0/go.mod h1:+GEjq9uNjqs8LQfM9nVnM8rff0OQ5Iash5rzX+N1CSg=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
mvdan.cc/xurls/v2 v2.5.0 h1:lyBNOm8Wo71UknhUs4QTFUNNMyxy2JEIaKKo0RWOh+8=
mvdan.cc/xurls/v2 v2.5.0/go.mod h1:yQgaGQ1rFtJUzkmKiHYSSfuQxqfYmd//X6PxvholpeE=
-10
View File
@@ -1,10 +0,0 @@
// Copyright 2022 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
/*
Package googlereader implements Google Reader API endpoints.
*/
package googlereader // import "miniflux.app/googlereader"
-10
View File
@@ -1,10 +0,0 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
/*
Package client provides an HTTP client builder.
*/
package client // import "miniflux.app/http/client"
-10
View File
@@ -1,10 +0,0 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
/*
Package cookie provides functions to build cookies.
*/
package cookie // import "miniflux.app/http/cookie"
-17
View File
@@ -1,17 +0,0 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
package request // import "miniflux.app/http/request"
import "net/http"
// CookieValue returns the cookie value.
func CookieValue(r *http.Request, name string) string {
cookie, err := r.Cookie(name)
if err == http.ErrNoCookie {
return ""
}
return cookie.Value
}
-10
View File
@@ -1,10 +0,0 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
/*
Package request contains helper functions to work with the HTTP request.
*/
package request // import "miniflux.app/http/request"
-10
View File
@@ -1,10 +0,0 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
/*
Package response contains everything related to HTTP responses.
*/
package response // import "miniflux.app/http/response"
-10
View File
@@ -1,10 +0,0 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
/*
Package html contains HTML response functions.
*/
package html // import "miniflux.app/http/response/html"
-10
View File
@@ -1,10 +0,0 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
/*
Package json contains JSON response functions.
*/
package json // import "miniflux.app/http/response/json"
-10
View File
@@ -1,10 +0,0 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
/*
Package xml contains XML response functions.
*/
package xml // import "miniflux.app/http/response/xml"
-10
View File
@@ -1,10 +0,0 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
/*
Package route contains helper functions to work with defined routes.
*/
package route // import "miniflux.app/http/route"
-69
View File
@@ -1,69 +0,0 @@
package espial // import "miniflux.app/integration/espial"
import (
"fmt"
"net/url"
"path"
"miniflux.app/http/client"
)
// Document structure of an Espial document
type Document struct {
Title string `json:"title,omitempty"`
Url string `json:"url,omitempty"`
ToRead bool `json:"toread,omitempty"`
Tags string `json:"tags,omitempty"`
}
// Client represents an Espial client.
type Client struct {
baseURL string
apiKey string
}
// NewClient returns a new Espial client.
func NewClient(baseURL, apiKey string) *Client {
return &Client{baseURL: baseURL, apiKey: apiKey}
}
// AddEntry sends an entry to Espial.
func (c *Client) AddEntry(link, title, content, tags string) error {
if c.baseURL == "" || c.apiKey == "" {
return fmt.Errorf("espial: missing credentials")
}
doc := &Document{
Title: title,
Url: link,
ToRead: true,
Tags: tags,
}
apiURL, err := getAPIEndpoint(c.baseURL, "/api/add")
if err != nil {
return err
}
clt := client.New(apiURL)
clt.WithAuthorization("ApiKey " + c.apiKey)
response, err := clt.PostJSON(doc)
if err != nil {
return fmt.Errorf("espial: unable to send entry: %v", err)
}
if response.HasServerFailure() {
return fmt.Errorf("espial: unable to send entry, status=%d", response.StatusCode)
}
return nil
}
func getAPIEndpoint(baseURL, pathURL string) (string, error) {
u, err := url.Parse(baseURL)
if err != nil {
return "", fmt.Errorf("espial: invalid API endpoint: %v", err)
}
u.Path = path.Join(u.Path, pathURL)
return u.String(), nil
}
-48
View File
@@ -1,48 +0,0 @@
// Copyright 2017 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
package instapaper // import "miniflux.app/integration/instapaper"
import (
"fmt"
"net/url"
"miniflux.app/http/client"
)
// Client represents an Instapaper client.
type Client struct {
username string
password string
}
// NewClient returns a new Instapaper client.
func NewClient(username, password string) *Client {
return &Client{username: username, password: password}
}
// AddURL sends a link to Instapaper.
func (c *Client) AddURL(link, title string) error {
if c.username == "" || c.password == "" {
return fmt.Errorf("instapaper: missing credentials")
}
values := url.Values{}
values.Add("url", link)
values.Add("title", title)
apiURL := "https://www.instapaper.com/api/add?" + values.Encode()
clt := client.New(apiURL)
clt.WithCredentials(c.username, c.password)
response, err := clt.Get()
if err != nil {
return fmt.Errorf("instapaper: unable to send url: %v", err)
}
if response.HasServerFailure() {
return fmt.Errorf("instapaper: unable to send url, status=%d", response.StatusCode)
}
return nil
}
-122
View File
@@ -1,122 +0,0 @@
// Copyright 2017 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
package integration // import "miniflux.app/integration"
import (
"miniflux.app/config"
"miniflux.app/integration/espial"
"miniflux.app/integration/instapaper"
"miniflux.app/integration/linkding"
"miniflux.app/integration/nunuxkeeper"
"miniflux.app/integration/pinboard"
"miniflux.app/integration/pocket"
"miniflux.app/integration/telegrambot"
"miniflux.app/integration/wallabag"
"miniflux.app/logger"
"miniflux.app/model"
)
// SendEntry sends the entry to third-party providers when the user click on "Save".
func SendEntry(entry *model.Entry, integration *model.Integration) {
if integration.PinboardEnabled {
logger.Debug("[Integration] Sending Entry #%d %q for User #%d to Pinboard", entry.ID, entry.URL, integration.UserID)
client := pinboard.NewClient(integration.PinboardToken)
err := client.AddBookmark(
entry.URL,
entry.Title,
integration.PinboardTags,
integration.PinboardMarkAsUnread,
)
if err != nil {
logger.Error("[Integration] UserID #%d: %v", integration.UserID, err)
}
}
if integration.InstapaperEnabled {
logger.Debug("[Integration] Sending Entry #%d %q for User #%d to Instapaper", entry.ID, entry.URL, integration.UserID)
client := instapaper.NewClient(integration.InstapaperUsername, integration.InstapaperPassword)
if err := client.AddURL(entry.URL, entry.Title); err != nil {
logger.Error("[Integration] UserID #%d: %v", integration.UserID, err)
}
}
if integration.WallabagEnabled {
logger.Debug("[Integration] Sending Entry #%d %q for User #%d to Wallabag", entry.ID, entry.URL, integration.UserID)
client := wallabag.NewClient(
integration.WallabagURL,
integration.WallabagClientID,
integration.WallabagClientSecret,
integration.WallabagUsername,
integration.WallabagPassword,
)
if err := client.AddEntry(entry.URL, entry.Title, entry.Content); err != nil {
logger.Error("[Integration] UserID #%d: %v", integration.UserID, err)
}
}
if integration.NunuxKeeperEnabled {
logger.Debug("[Integration] Sending Entry #%d %q for User #%d to NunuxKeeper", entry.ID, entry.URL, integration.UserID)
client := nunuxkeeper.NewClient(
integration.NunuxKeeperURL,
integration.NunuxKeeperAPIKey,
)
if err := client.AddEntry(entry.URL, entry.Title, entry.Content); err != nil {
logger.Error("[Integration] UserID #%d: %v", integration.UserID, err)
}
}
if integration.EspialEnabled {
logger.Debug("[Integration] Sending Entry #%d %q for User #%d to Espial", entry.ID, entry.URL, integration.UserID)
client := espial.NewClient(
integration.EspialURL,
integration.EspialAPIKey,
)
if err := client.AddEntry(entry.URL, entry.Title, entry.Content, integration.EspialTags); err != nil {
logger.Error("[Integration] UserID #%d: %v", integration.UserID, err)
}
}
if integration.PocketEnabled {
logger.Debug("[Integration] Sending Entry #%d %q for User #%d to Pocket", entry.ID, entry.URL, integration.UserID)
client := pocket.NewClient(config.Opts.PocketConsumerKey(integration.PocketConsumerKey), integration.PocketAccessToken)
if err := client.AddURL(entry.URL, entry.Title); err != nil {
logger.Error("[Integration] UserID #%d: %v", integration.UserID, err)
}
}
if integration.LinkdingEnabled {
logger.Debug("[Integration] Sending Entry #%d %q for User #%d to Linkding", entry.ID, entry.URL, integration.UserID)
client := linkding.NewClient(
integration.LinkdingURL,
integration.LinkdingAPIKey,
)
if err := client.AddEntry(entry.Title, entry.URL); err != nil {
logger.Error("[Integration] UserID #%d: %v", integration.UserID, err)
}
}
}
// PushEntry pushes an entry to third-party providers during feed refreshes.
func PushEntry(entry *model.Entry, integration *model.Integration) {
if integration.TelegramBotEnabled {
logger.Debug("[Integration] Sending Entry %q for User #%d to Telegram", entry.URL, integration.UserID)
err := telegrambot.PushEntry(entry, integration.TelegramBotToken, integration.TelegramBotChatID)
if err != nil {
logger.Error("[Integration] push entry to telegram bot failed: %v", err)
}
}
}
-74
View File
@@ -1,74 +0,0 @@
// Copyright 2017 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
package linkding // import "miniflux.app/integration/linkding"
import (
"fmt"
"net/url"
"miniflux.app/http/client"
)
// Document structure of a Linkding document
type Document struct {
Url string `json:"url,omitempty"`
Title string `json:"title,omitempty"`
}
// Client represents an Linkding client.
type Client struct {
baseURL string
apiKey string
}
// NewClient returns a new Linkding client.
func NewClient(baseURL, apiKey string) *Client {
return &Client{baseURL: baseURL, apiKey: apiKey}
}
// AddEntry sends an entry to Linkding.
func (c *Client) AddEntry(title, url string) error {
if c.baseURL == "" || c.apiKey == "" {
return fmt.Errorf("linkding: missing credentials")
}
doc := &Document{
Url: url,
Title: title,
}
apiURL, err := getAPIEndpoint(c.baseURL, "/api/bookmarks/")
if err != nil {
return err
}
clt := client.New(apiURL)
clt.WithAuthorization("Token " + c.apiKey)
response, err := clt.PostJSON(doc)
if err != nil {
return fmt.Errorf("linkding: unable to send entry: %v", err)
}
if response.HasServerFailure() {
return fmt.Errorf("linkding: unable to send entry, status=%d", response.StatusCode)
}
return nil
}
func getAPIEndpoint(baseURL, pathURL string) (string, error) {
u, err := url.Parse(baseURL)
if err != nil {
return "", fmt.Errorf("linkding: invalid API endpoint: %v", err)
}
relative, err := url.Parse(pathURL)
if err != nil {
return "", fmt.Errorf("linkding: invalid API endpoint: %v", err)
}
u = u.ResolveReference(relative)
return u.String(), nil
}
-73
View File
@@ -1,73 +0,0 @@
// Copyright 2017 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
package nunuxkeeper // import "miniflux.app/integration/nunuxkeeper"
import (
"fmt"
"net/url"
"path"
"miniflux.app/http/client"
)
// Document structure of a Nununx Keeper document
type Document struct {
Title string `json:"title,omitempty"`
Origin string `json:"origin,omitempty"`
Content string `json:"content,omitempty"`
ContentType string `json:"contentType,omitempty"`
}
// Client represents an Nunux Keeper client.
type Client struct {
baseURL string
apiKey string
}
// NewClient returns a new Nunux Keeepr client.
func NewClient(baseURL, apiKey string) *Client {
return &Client{baseURL: baseURL, apiKey: apiKey}
}
// AddEntry sends an entry to Nunux Keeper.
func (c *Client) AddEntry(link, title, content string) error {
if c.baseURL == "" || c.apiKey == "" {
return fmt.Errorf("nunux-keeper: missing credentials")
}
doc := &Document{
Title: title,
Origin: link,
Content: content,
ContentType: "text/html",
}
apiURL, err := getAPIEndpoint(c.baseURL, "/v2/documents")
if err != nil {
return err
}
clt := client.New(apiURL)
clt.WithCredentials("api", c.apiKey)
response, err := clt.PostJSON(doc)
if err != nil {
return fmt.Errorf("nunux-keeper: unable to send entry: %v", err)
}
if response.HasServerFailure() {
return fmt.Errorf("nunux-keeper: unable to send entry, status=%d", response.StatusCode)
}
return nil
}
func getAPIEndpoint(baseURL, pathURL string) (string, error) {
u, err := url.Parse(baseURL)
if err != nil {
return "", fmt.Errorf("nunux-keeper: invalid API endpoint: %v", err)
}
u.Path = path.Join(u.Path, pathURL)
return u.String(), nil
}
-53
View File
@@ -1,53 +0,0 @@
// Copyright 2017 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
package pinboard // import "miniflux.app/integration/pinboard"
import (
"fmt"
"net/url"
"miniflux.app/http/client"
)
// Client represents a Pinboard client.
type Client struct {
authToken string
}
// NewClient returns a new Pinboard client.
func NewClient(authToken string) *Client {
return &Client{authToken: authToken}
}
// AddBookmark sends a link to Pinboard.
func (c *Client) AddBookmark(link, title, tags string, markAsUnread bool) error {
if c.authToken == "" {
return fmt.Errorf("pinboard: missing credentials")
}
toRead := "no"
if markAsUnread {
toRead = "yes"
}
values := url.Values{}
values.Add("auth_token", c.authToken)
values.Add("url", link)
values.Add("description", title)
values.Add("tags", tags)
values.Add("toread", toRead)
clt := client.New("https://api.pinboard.in/v1/posts/add?" + values.Encode())
response, err := clt.Get()
if err != nil {
return fmt.Errorf("pinboard: unable to send bookmark: %v", err)
}
if response.HasServerFailure() {
return fmt.Errorf("pinboard: unable to send bookmark, status=%d", response.StatusCode)
}
return nil
}
-103
View File
@@ -1,103 +0,0 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
package pocket // import "miniflux.app/integration/pocket"
import (
"errors"
"fmt"
"io"
"net/url"
"miniflux.app/http/client"
)
// Connector manages the authorization flow with Pocket to get a personal access token.
type Connector struct {
consumerKey string
}
// NewConnector returns a new Pocket Connector.
func NewConnector(consumerKey string) *Connector {
return &Connector{consumerKey}
}
// RequestToken fetches a new request token from Pocket API.
func (c *Connector) RequestToken(redirectURL string) (string, error) {
type req struct {
ConsumerKey string `json:"consumer_key"`
RedirectURI string `json:"redirect_uri"`
}
clt := client.New("https://getpocket.com/v3/oauth/request")
response, err := clt.PostJSON(&req{ConsumerKey: c.consumerKey, RedirectURI: redirectURL})
if err != nil {
return "", fmt.Errorf("pocket: unable to fetch request token: %v", err)
}
if response.HasServerFailure() {
return "", fmt.Errorf("pocket: unable to fetch request token, status=%d", response.StatusCode)
}
body, err := io.ReadAll(response.Body)
if err != nil {
return "", fmt.Errorf("pocket: unable to read response body: %v", err)
}
values, err := url.ParseQuery(string(body))
if err != nil {
return "", fmt.Errorf("pocket: unable to parse response: %v", err)
}
code := values.Get("code")
if code == "" {
return "", errors.New("pocket: code is empty")
}
return code, nil
}
// AccessToken fetches a new access token once the end-user authorized the application.
func (c *Connector) AccessToken(requestToken string) (string, error) {
type req struct {
ConsumerKey string `json:"consumer_key"`
Code string `json:"code"`
}
clt := client.New("https://getpocket.com/v3/oauth/authorize")
response, err := clt.PostJSON(&req{ConsumerKey: c.consumerKey, Code: requestToken})
if err != nil {
return "", fmt.Errorf("pocket: unable to fetch access token: %v", err)
}
if response.HasServerFailure() {
return "", fmt.Errorf("pocket: unable to fetch access token, status=%d", response.StatusCode)
}
body, err := io.ReadAll(response.Body)
if err != nil {
return "", fmt.Errorf("pocket: unable to read response body: %v", err)
}
values, err := url.ParseQuery(string(body))
if err != nil {
return "", fmt.Errorf("pocket: unable to parse response: %v", err)
}
token := values.Get("access_token")
if token == "" {
return "", errors.New("pocket: access_token is empty")
}
return token, nil
}
// AuthorizationURL returns the authorization URL for the end-user.
func (c *Connector) AuthorizationURL(requestToken, redirectURL string) string {
return fmt.Sprintf(
"https://getpocket.com/auth/authorize?request_token=%s&redirect_uri=%s",
requestToken,
redirectURL,
)
}
-55
View File
@@ -1,55 +0,0 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
package pocket // import "miniflux.app/integration/pocket"
import (
"fmt"
"miniflux.app/http/client"
)
// Client represents a Pocket client.
type Client struct {
consumerKey string
accessToken string
}
// NewClient returns a new Pocket client.
func NewClient(consumerKey, accessToken string) *Client {
return &Client{consumerKey, accessToken}
}
// AddURL sends a single link to Pocket.
func (c *Client) AddURL(link, title string) error {
if c.consumerKey == "" || c.accessToken == "" {
return fmt.Errorf("pocket: missing credentials")
}
type body struct {
AccessToken string `json:"access_token"`
ConsumerKey string `json:"consumer_key"`
Title string `json:"title,omitempty"`
URL string `json:"url"`
}
data := &body{
AccessToken: c.accessToken,
ConsumerKey: c.consumerKey,
Title: title,
URL: link,
}
clt := client.New("https://getpocket.com/v3/add")
response, err := clt.PostJSON(data)
if err != nil {
return fmt.Errorf("pocket: unable to send url: %v", err)
}
if response.HasServerFailure() {
return fmt.Errorf("pocket: unable to send url, status=%d", response.StatusCode)
}
return nil
}
-122
View File
@@ -1,122 +0,0 @@
// Copyright 2017 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
package wallabag // import "miniflux.app/integration/wallabag"
import (
"encoding/json"
"fmt"
"io"
"net/url"
"miniflux.app/http/client"
)
// Client represents a Wallabag client.
type Client struct {
baseURL string
clientID string
clientSecret string
username string
password string
}
// NewClient returns a new Wallabag client.
func NewClient(baseURL, clientID, clientSecret, username, password string) *Client {
return &Client{baseURL, clientID, clientSecret, username, password}
}
// AddEntry sends a link to Wallabag.
// Pass an empty string in `content` to let Wallabag fetch the article content.
func (c *Client) AddEntry(link, title, content string) error {
if c.baseURL == "" || c.clientID == "" || c.clientSecret == "" || c.username == "" || c.password == "" {
return fmt.Errorf("wallabag: missing credentials")
}
accessToken, err := c.getAccessToken()
if err != nil {
return err
}
return c.createEntry(accessToken, link, title, content)
}
func (c *Client) createEntry(accessToken, link, title, content string) error {
endpoint, err := getAPIEndpoint(c.baseURL, "/api/entries.json")
if err != nil {
return fmt.Errorf("wallbag: unable to get entries endpoint: %v", err)
}
clt := client.New(endpoint)
clt.WithAuthorization("Bearer " + accessToken)
response, err := clt.PostJSON(map[string]string{"url": link, "title": title, "content": content})
if err != nil {
return fmt.Errorf("wallabag: unable to post entry: %v", err)
}
if response.HasServerFailure() {
return fmt.Errorf("wallabag: request failed, status=%d", response.StatusCode)
}
return nil
}
func (c *Client) getAccessToken() (string, error) {
values := url.Values{}
values.Add("grant_type", "password")
values.Add("client_id", c.clientID)
values.Add("client_secret", c.clientSecret)
values.Add("username", c.username)
values.Add("password", c.password)
endpoint, err := getAPIEndpoint(c.baseURL, "/oauth/v2/token")
if err != nil {
return "", fmt.Errorf("wallbag: unable to get token endpoint: %v", err)
}
clt := client.New(endpoint)
response, err := clt.PostForm(values)
if err != nil {
return "", fmt.Errorf("wallabag: unable to get access token: %v", err)
}
if response.HasServerFailure() {
return "", fmt.Errorf("wallabag: request failed, status=%d", response.StatusCode)
}
token, err := decodeTokenResponse(response.Body)
if err != nil {
return "", err
}
return token.AccessToken, nil
}
func getAPIEndpoint(baseURL, path string) (string, error) {
u, err := url.Parse(baseURL)
if err != nil {
return "", fmt.Errorf("wallabag: invalid API endpoint: %v", err)
}
u.Path = path
return u.String(), nil
}
type tokenResponse struct {
AccessToken string `json:"access_token"`
Expires int `json:"expires_in"`
RefreshToken string `json:"refresh_token"`
Scope string `json:"scope"`
TokenType string `json:"token_type"`
}
func decodeTokenResponse(body io.Reader) (*tokenResponse, error) {
var token tokenResponse
decoder := json.NewDecoder(body)
if err := decoder.Decode(&token); err != nil {
return nil, fmt.Errorf("wallabag: unable to decode token response: %v", err)
}
return &token, nil
}
+11 -9
View File
@@ -1,26 +1,26 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package api // import "miniflux.app/api"
package api // import "miniflux.app/v2/internal/api"
import (
"net/http"
"miniflux.app/storage"
"miniflux.app/worker"
"miniflux.app/v2/internal/storage"
"miniflux.app/v2/internal/worker"
"github.com/gorilla/mux"
)
type handler struct {
store *storage.Storage
pool *worker.Pool
store *storage.Storage
pool *worker.Pool
router *mux.Router
}
// Serve declares API routes for the application.
func Serve(router *mux.Router, store *storage.Storage, pool *worker.Pool) {
handler := &handler{store, pool}
handler := &handler{store, pool, router}
sr := router.PathPrefix("/v1").Subrouter()
middleware := newMiddleware(store)
@@ -42,6 +42,7 @@ func Serve(router *mux.Router, store *storage.Storage, pool *worker.Pool) {
sr.HandleFunc("/categories/{categoryID}", handler.removeCategory).Methods(http.MethodDelete)
sr.HandleFunc("/categories/{categoryID}/mark-all-as-read", handler.markCategoryAsRead).Methods(http.MethodPut)
sr.HandleFunc("/categories/{categoryID}/feeds", handler.getCategoryFeeds).Methods(http.MethodGet)
sr.HandleFunc("/categories/{categoryID}/refresh", handler.refreshCategory).Methods(http.MethodPut)
sr.HandleFunc("/categories/{categoryID}/entries", handler.getCategoryEntries).Methods(http.MethodGet)
sr.HandleFunc("/categories/{categoryID}/entries/{entryID}", handler.getCategoryEntry).Methods(http.MethodGet)
sr.HandleFunc("/discover", handler.discoverSubscriptions).Methods(http.MethodPost)
@@ -63,5 +64,6 @@ func Serve(router *mux.Router, store *storage.Storage, pool *worker.Pool) {
sr.HandleFunc("/entries", handler.setEntryStatus).Methods(http.MethodPut)
sr.HandleFunc("/entries/{entryID}", handler.getEntry).Methods(http.MethodGet)
sr.HandleFunc("/entries/{entryID}/bookmark", handler.toggleBookmark).Methods(http.MethodPut)
sr.HandleFunc("/entries/{entryID}/save", handler.saveEntry).Methods(http.MethodPost)
sr.HandleFunc("/entries/{entryID}/fetch-content", handler.fetchContent).Methods(http.MethodGet)
}
+34 -10
View File
@@ -1,18 +1,17 @@
// Copyright 2017 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package api // import "miniflux.app/api"
package api // import "miniflux.app/v2/internal/api"
import (
json_parser "encoding/json"
"net/http"
"time"
"miniflux.app/http/request"
"miniflux.app/http/response/json"
"miniflux.app/model"
"miniflux.app/validator"
"miniflux.app/v2/internal/http/request"
"miniflux.app/v2/internal/http/response/json"
"miniflux.app/v2/internal/model"
"miniflux.app/v2/internal/validator"
)
func (h *handler) createCategory(w http.ResponseWriter, r *http.Request) {
@@ -98,12 +97,20 @@ func (h *handler) markCategoryAsRead(w http.ResponseWriter, r *http.Request) {
}
func (h *handler) getCategories(w http.ResponseWriter, r *http.Request) {
categories, err := h.store.Categories(request.UserID(r))
var categories model.Categories
var err error
includeCounts := request.QueryStringParam(r, "counts", "false")
if includeCounts == "true" {
categories, err = h.store.CategoriesWithFeedCount(request.UserID(r))
} else {
categories, err = h.store.Categories(request.UserID(r))
}
if err != nil {
json.ServerError(w, r, err)
return
}
json.OK(w, r, categories)
}
@@ -123,3 +130,20 @@ func (h *handler) removeCategory(w http.ResponseWriter, r *http.Request) {
json.NoContent(w, r)
}
func (h *handler) refreshCategory(w http.ResponseWriter, r *http.Request) {
userID := request.UserID(r)
categoryID := request.RouteInt64Param(r, "categoryID")
jobs, err := h.store.NewCategoryBatch(userID, categoryID, h.store.CountFeeds(userID))
if err != nil {
json.ServerError(w, r, err)
return
}
go func() {
h.pool.Push(jobs)
}()
json.NoContent(w, r)
}
+87 -19
View File
@@ -1,25 +1,29 @@
// Copyright 2017 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package api // import "miniflux.app/api"
package api // import "miniflux.app/v2/internal/api"
import (
json_parser "encoding/json"
"errors"
"net/http"
"strconv"
"strings"
"time"
"miniflux.app/http/request"
"miniflux.app/http/response/json"
"miniflux.app/model"
"miniflux.app/reader/processor"
"miniflux.app/storage"
"miniflux.app/validator"
"miniflux.app/v2/internal/config"
"miniflux.app/v2/internal/http/request"
"miniflux.app/v2/internal/http/response/json"
"miniflux.app/v2/internal/integration"
"miniflux.app/v2/internal/model"
"miniflux.app/v2/internal/proxy"
"miniflux.app/v2/internal/reader/processor"
"miniflux.app/v2/internal/storage"
"miniflux.app/v2/internal/urllib"
"miniflux.app/v2/internal/validator"
)
func getEntryFromBuilder(w http.ResponseWriter, r *http.Request, b *storage.EntryQueryBuilder) {
func (h *handler) getEntryFromBuilder(w http.ResponseWriter, r *http.Request, b *storage.EntryQueryBuilder) {
entry, err := b.GetEntry()
if err != nil {
json.ServerError(w, r, err)
@@ -31,6 +35,20 @@ func getEntryFromBuilder(w http.ResponseWriter, r *http.Request, b *storage.Entr
return
}
entry.Content = proxy.AbsoluteProxyRewriter(h.router, r.Host, entry.Content)
proxyOption := config.Opts.ProxyOption()
for i := range entry.Enclosures {
if proxyOption == "all" || proxyOption != "none" && !urllib.IsHTTPS(entry.Enclosures[i].URL) {
for _, mediaType := range config.Opts.ProxyMediaTypes() {
if strings.HasPrefix(entry.Enclosures[i].MimeType, mediaType+"/") {
entry.Enclosures[i].URL = proxy.AbsoluteProxifyURL(h.router, r.Host, entry.Enclosures[i].URL)
break
}
}
}
}
json.OK(w, r, entry)
}
@@ -42,7 +60,7 @@ func (h *handler) getFeedEntry(w http.ResponseWriter, r *http.Request) {
builder.WithFeedID(feedID)
builder.WithEntryID(entryID)
getEntryFromBuilder(w, r, builder)
h.getEntryFromBuilder(w, r, builder)
}
func (h *handler) getCategoryEntry(w http.ResponseWriter, r *http.Request) {
@@ -53,7 +71,7 @@ func (h *handler) getCategoryEntry(w http.ResponseWriter, r *http.Request) {
builder.WithCategoryID(categoryID)
builder.WithEntryID(entryID)
getEntryFromBuilder(w, r, builder)
h.getEntryFromBuilder(w, r, builder)
}
func (h *handler) getEntry(w http.ResponseWriter, r *http.Request) {
@@ -61,7 +79,7 @@ func (h *handler) getEntry(w http.ResponseWriter, r *http.Request) {
builder := h.store.NewEntryQueryBuilder(request.UserID(r))
builder.WithEntryID(entryID)
getEntryFromBuilder(w, r, builder)
h.getEntryFromBuilder(w, r, builder)
}
func (h *handler) getFeedEntries(w http.ResponseWriter, r *http.Request) {
@@ -109,24 +127,26 @@ func (h *handler) findEntries(w http.ResponseWriter, r *http.Request, feedID int
userID := request.UserID(r)
categoryID = request.QueryInt64Param(r, "category_id", categoryID)
if categoryID > 0 && !h.store.CategoryIDExists(userID, categoryID) {
json.BadRequest(w, r, errors.New("Invalid category ID"))
json.BadRequest(w, r, errors.New("invalid category ID"))
return
}
feedID = request.QueryInt64Param(r, "feed_id", feedID)
if feedID > 0 && !h.store.FeedExists(userID, feedID) {
json.BadRequest(w, r, errors.New("Invalid feed ID"))
json.BadRequest(w, r, errors.New("invalid feed ID"))
return
}
tags := request.QueryStringParamList(r, "tags")
builder := h.store.NewEntryQueryBuilder(userID)
builder.WithFeedID(feedID)
builder.WithCategoryID(categoryID)
builder.WithStatuses(statuses)
builder.WithOrder(order)
builder.WithDirection(direction)
builder.WithSorting(order, direction)
builder.WithOffset(offset)
builder.WithLimit(limit)
builder.WithTags(tags)
configureFilters(builder, r)
entries, err := builder.GetEntries()
@@ -141,6 +161,10 @@ func (h *handler) findEntries(w http.ResponseWriter, r *http.Request, feedID int
return
}
for i := range entries {
entries[i].Content = proxy.AbsoluteProxyRewriter(h.router, r.Host, entries[i].Content)
}
json.OK(w, r, &entriesResponse{Total: count, Entries: entries})
}
@@ -174,6 +198,39 @@ func (h *handler) toggleBookmark(w http.ResponseWriter, r *http.Request) {
json.NoContent(w, r)
}
func (h *handler) saveEntry(w http.ResponseWriter, r *http.Request) {
entryID := request.RouteInt64Param(r, "entryID")
builder := h.store.NewEntryQueryBuilder(request.UserID(r))
builder.WithEntryID(entryID)
builder.WithoutStatus(model.EntryStatusRemoved)
if !h.store.HasSaveEntry(request.UserID(r)) {
json.BadRequest(w, r, errors.New("no third-party integration enabled"))
return
}
entry, err := builder.GetEntry()
if err != nil {
json.ServerError(w, r, err)
return
}
if entry == nil {
json.NotFound(w, r)
return
}
settings, err := h.store.Integration(request.UserID(r))
if err != nil {
json.ServerError(w, r, err)
return
}
go integration.SendEntry(entry, settings)
json.Accepted(w, r)
}
func (h *handler) fetchContent(w http.ResponseWriter, r *http.Request) {
loggedUserID := request.UserID(r)
entryID := request.RouteInt64Param(r, "entryID")
@@ -193,6 +250,17 @@ func (h *handler) fetchContent(w http.ResponseWriter, r *http.Request) {
return
}
user, err := h.store.UserByID(entry.UserID)
if err != nil {
json.ServerError(w, r, err)
return
}
if user == nil {
json.NotFound(w, r)
return
}
feedBuilder := storage.NewFeedQueryBuilder(h.store, loggedUserID)
feedBuilder.WithFeedID(entry.FeedID)
feed, err := feedBuilder.GetFeed()
@@ -206,7 +274,7 @@ func (h *handler) fetchContent(w http.ResponseWriter, r *http.Request) {
return
}
if err := processor.ProcessEntryWebPage(feed, entry); err != nil {
if err := processor.ProcessEntryWebPage(feed, entry, user); err != nil {
json.ServerError(w, r, err)
return
}
+9 -10
View File
@@ -1,19 +1,18 @@
// Copyright 2017 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package api // import "miniflux.app/api"
package api // import "miniflux.app/v2/internal/api"
import (
json_parser "encoding/json"
"net/http"
"time"
"miniflux.app/http/request"
"miniflux.app/http/response/json"
"miniflux.app/model"
feedHandler "miniflux.app/reader/handler"
"miniflux.app/validator"
"miniflux.app/v2/internal/http/request"
"miniflux.app/v2/internal/http/response/json"
"miniflux.app/v2/internal/model"
feedHandler "miniflux.app/v2/internal/reader/handler"
"miniflux.app/v2/internal/validator"
)
func (h *handler) createFeed(w http.ResponseWriter, r *http.Request) {
@@ -48,7 +47,7 @@ func (h *handler) refreshFeed(w http.ResponseWriter, r *http.Request) {
return
}
err := feedHandler.RefreshFeed(h.store, userID, feedID)
err := feedHandler.RefreshFeed(h.store, userID, feedID, false)
if err != nil {
json.ServerError(w, r, err)
return
+5 -6
View File
@@ -1,14 +1,13 @@
// Copyright 2017 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package api // import "miniflux.app/api"
package api // import "miniflux.app/v2/internal/api"
import (
"net/http"
"miniflux.app/http/request"
"miniflux.app/http/response/json"
"miniflux.app/v2/internal/http/request"
"miniflux.app/v2/internal/http/response/json"
)
func (h *handler) feedIcon(w http.ResponseWriter, r *http.Request) {
@@ -1,17 +1,16 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package api // import "miniflux.app/api"
package api // import "miniflux.app/v2/internal/api"
import (
"context"
"net/http"
"miniflux.app/http/request"
"miniflux.app/http/response/json"
"miniflux.app/logger"
"miniflux.app/storage"
"miniflux.app/v2/internal/http/request"
"miniflux.app/v2/internal/http/response/json"
"miniflux.app/v2/internal/logger"
"miniflux.app/v2/internal/storage"
)
type middleware struct {
@@ -25,7 +24,7 @@ func (m *middleware) handleCORS(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "X-Auth-Token")
w.Header().Set("Access-Control-Allow-Headers", "X-Auth-Token, Authorization, Content-Type, Accept")
if r.Method == http.MethodOptions {
w.Header().Set("Access-Control-Max-Age", "3600")
w.WriteHeader(http.StatusOK)
+7 -8
View File
@@ -1,16 +1,15 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package api // import "miniflux.app/api"
package api // import "miniflux.app/v2/internal/api"
import (
"net/http"
"miniflux.app/http/request"
"miniflux.app/http/response/json"
"miniflux.app/http/response/xml"
"miniflux.app/reader/opml"
"miniflux.app/v2/internal/http/request"
"miniflux.app/v2/internal/http/response/json"
"miniflux.app/v2/internal/http/response/xml"
"miniflux.app/v2/internal/reader/opml"
)
func (h *handler) exportFeeds(w http.ResponseWriter, r *http.Request) {
+4 -5
View File
@@ -1,11 +1,10 @@
// Copyright 2017 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package api // import "miniflux.app/api"
package api // import "miniflux.app/v2/internal/api"
import (
"miniflux.app/model"
"miniflux.app/v2/internal/model"
)
type feedIconResponse struct {
@@ -1,17 +1,16 @@
// Copyright 2017 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package api // import "miniflux.app/api"
package api // import "miniflux.app/v2/internal/api"
import (
json_parser "encoding/json"
"net/http"
"miniflux.app/http/response/json"
"miniflux.app/model"
"miniflux.app/reader/subscription"
"miniflux.app/validator"
"miniflux.app/v2/internal/http/response/json"
"miniflux.app/v2/internal/model"
"miniflux.app/v2/internal/reader/subscription"
"miniflux.app/v2/internal/validator"
)
func (h *handler) discoverSubscriptions(w http.ResponseWriter, r *http.Request) {
+7 -8
View File
@@ -1,18 +1,17 @@
// Copyright 2017 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package api // import "miniflux.app/api"
package api // import "miniflux.app/v2/internal/api"
import (
json_parser "encoding/json"
"errors"
"net/http"
"miniflux.app/http/request"
"miniflux.app/http/response/json"
"miniflux.app/model"
"miniflux.app/validator"
"miniflux.app/v2/internal/http/request"
"miniflux.app/v2/internal/http/response/json"
"miniflux.app/v2/internal/model"
"miniflux.app/v2/internal/validator"
)
func (h *handler) currentUser(w http.ResponseWriter, r *http.Request) {
@@ -1,8 +1,7 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package cli // import "miniflux.app/cli"
package cli // import "miniflux.app/v2/internal/cli"
import (
"bufio"
@@ -10,13 +9,13 @@ import (
"os"
"strings"
"golang.org/x/crypto/ssh/terminal"
"golang.org/x/term"
)
func askCredentials() (string, string) {
fd := int(os.Stdin.Fd())
if !terminal.IsTerminal(fd) {
if !term.IsTerminal(fd) {
fmt.Fprintf(os.Stderr, "This is not a terminal, exiting.\n")
os.Exit(1)
}
@@ -28,9 +27,9 @@ func askCredentials() (string, string) {
fmt.Print("Enter Password: ")
state, _ := terminal.GetState(fd)
defer terminal.Restore(fd, state)
bytePassword, _ := terminal.ReadPassword(fd)
state, _ := term.GetState(fd)
defer term.Restore(fd, state)
bytePassword, _ := term.ReadPassword(fd)
fmt.Printf("\n")
return strings.TrimSpace(username), strings.TrimSpace(string(bytePassword))
+42
View File
@@ -0,0 +1,42 @@
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package cli // import "miniflux.app/v2/internal/cli"
import (
"time"
"miniflux.app/v2/internal/config"
"miniflux.app/v2/internal/logger"
"miniflux.app/v2/internal/metric"
"miniflux.app/v2/internal/model"
"miniflux.app/v2/internal/storage"
)
func runCleanupTasks(store *storage.Storage) {
nbSessions := store.CleanOldSessions(config.Opts.CleanupRemoveSessionsDays())
nbUserSessions := store.CleanOldUserSessions(config.Opts.CleanupRemoveSessionsDays())
logger.Info("[Sessions] Removed %d application sessions and %d user sessions", nbSessions, nbUserSessions)
startTime := time.Now()
if rowsAffected, err := store.ArchiveEntries(model.EntryStatusRead, config.Opts.CleanupArchiveReadDays(), config.Opts.CleanupArchiveBatchSize()); err != nil {
logger.Error("[ArchiveReadEntries] %v", err)
} else {
logger.Info("[ArchiveReadEntries] %d entries changed", rowsAffected)
if config.Opts.HasMetricsCollector() {
metric.ArchiveEntriesDuration.WithLabelValues(model.EntryStatusRead).Observe(time.Since(startTime).Seconds())
}
}
startTime = time.Now()
if rowsAffected, err := store.ArchiveEntries(model.EntryStatusUnread, config.Opts.CleanupArchiveUnreadDays(), config.Opts.CleanupArchiveBatchSize()); err != nil {
logger.Error("[ArchiveUnreadEntries] %v", err)
} else {
logger.Info("[ArchiveUnreadEntries] %d entries changed", rowsAffected)
if config.Opts.HasMetricsCollector() {
metric.ArchiveEntriesDuration.WithLabelValues(model.EntryStatusUnread).Observe(time.Since(startTime).Seconds())
}
}
}
+27 -12
View File
@@ -1,24 +1,23 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package cli // import "miniflux.app/cli"
package cli // import "miniflux.app/v2/internal/cli"
import (
"flag"
"fmt"
"miniflux.app/config"
"miniflux.app/database"
"miniflux.app/locale"
"miniflux.app/logger"
"miniflux.app/storage"
"miniflux.app/ui/static"
"miniflux.app/version"
"miniflux.app/v2/internal/config"
"miniflux.app/v2/internal/database"
"miniflux.app/v2/internal/locale"
"miniflux.app/v2/internal/logger"
"miniflux.app/v2/internal/storage"
"miniflux.app/v2/internal/ui/static"
"miniflux.app/v2/internal/version"
)
const (
flagInfoHelp = "Show application information"
flagInfoHelp = "Show build information"
flagVersionHelp = "Show application version"
flagMigrateHelp = "Run SQL migrations"
flagFlushSessionsHelp = "Flush all sessions (disconnect users)"
@@ -29,6 +28,8 @@ const (
flagConfigFileHelp = "Load configuration file"
flagConfigDumpHelp = "Print parsed configuration values"
flagHealthCheckHelp = `Perform a health check on the given endpoint (the value "auto" try to guess the health check endpoint).`
flagRefreshFeedsHelp = "Refresh a batch of feeds and exit"
flagRunCleanupTasksHelp = "Run cleanup tasks (delete old sessions and archives old entries)"
)
// Parse parses command line arguments.
@@ -46,6 +47,8 @@ func Parse() {
flagConfigFile string
flagConfigDump bool
flagHealthCheck string
flagRefreshFeeds bool
flagRunCleanupTasks bool
)
flag.BoolVar(&flagInfo, "info", false, flagInfoHelp)
@@ -62,6 +65,8 @@ func Parse() {
flag.StringVar(&flagConfigFile, "c", "", flagConfigFileHelp)
flag.BoolVar(&flagConfigDump, "config-dump", false, flagConfigDumpHelp)
flag.StringVar(&flagHealthCheck, "healthcheck", "", flagHealthCheckHelp)
flag.BoolVar(&flagRefreshFeeds, "refresh-feeds", false, flagRefreshFeedsHelp)
flag.BoolVar(&flagRunCleanupTasks, "run-cleanup-tasks", false, flagRunCleanupTasksHelp)
flag.Parse()
cfg := config.NewParser()
@@ -188,5 +193,15 @@ func Parse() {
createAdmin(store)
}
if flagRefreshFeeds {
refreshFeeds(store)
return
}
if flagRunCleanupTasks {
runCleanupTasks(store)
return
}
startDaemon(store)
}
@@ -1,18 +1,17 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package cli // import "miniflux.app/cli"
package cli // import "miniflux.app/v2/internal/cli"
import (
"fmt"
"os"
"miniflux.app/config"
"miniflux.app/logger"
"miniflux.app/model"
"miniflux.app/storage"
"miniflux.app/validator"
"miniflux.app/v2/internal/config"
"miniflux.app/v2/internal/logger"
"miniflux.app/v2/internal/model"
"miniflux.app/v2/internal/storage"
"miniflux.app/v2/internal/validator"
)
func createAdmin(store *storage.Storage) {
+13 -15
View File
@@ -1,8 +1,7 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package cli // import "miniflux.app/cli"
package cli // import "miniflux.app/v2/internal/cli"
import (
"context"
@@ -12,18 +11,17 @@ import (
"syscall"
"time"
"miniflux.app/config"
"miniflux.app/logger"
"miniflux.app/metric"
"miniflux.app/service/httpd"
"miniflux.app/service/scheduler"
"miniflux.app/storage"
"miniflux.app/systemd"
"miniflux.app/worker"
"miniflux.app/v2/internal/config"
httpd "miniflux.app/v2/internal/http/server"
"miniflux.app/v2/internal/logger"
"miniflux.app/v2/internal/metric"
"miniflux.app/v2/internal/storage"
"miniflux.app/v2/internal/systemd"
"miniflux.app/v2/internal/worker"
)
func startDaemon(store *storage.Storage) {
logger.Info("Starting Miniflux...")
logger.Info("Starting daemon...")
stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt)
@@ -32,12 +30,12 @@ func startDaemon(store *storage.Storage) {
pool := worker.NewPool(store, config.Opts.WorkerPoolSize())
if config.Opts.HasSchedulerService() && !config.Opts.HasMaintenanceMode() {
scheduler.Serve(store, pool)
runScheduler(store, pool)
}
var httpServer *http.Server
if config.Opts.HasHTTPService() {
httpServer = httpd.Serve(store, pool)
httpServer = httpd.StartWebServer(store, pool)
}
if config.Opts.HasMetricsCollector() {
@@ -1,14 +1,13 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package cli // import "miniflux.app/cli"
package cli // import "miniflux.app/v2/internal/cli"
import (
"fmt"
"os"
"miniflux.app/storage"
"miniflux.app/v2/internal/storage"
)
func flushSessions(store *storage.Storage) {
@@ -1,15 +1,14 @@
// Copyright 2021 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package cli // import "miniflux.app/cli"
package cli // import "miniflux.app/v2/internal/cli"
import (
"net/http"
"time"
"miniflux.app/config"
"miniflux.app/logger"
"miniflux.app/v2/internal/config"
"miniflux.app/v2/internal/logger"
)
func doHealthCheck(healthCheckEndpoint string) {
+4 -5
View File
@@ -1,14 +1,13 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package cli // import "miniflux.app/cli"
package cli // import "miniflux.app/v2/internal/cli"
import (
"fmt"
"runtime"
"miniflux.app/version"
"miniflux.app/v2/internal/version"
)
func info() {
+51
View File
@@ -0,0 +1,51 @@
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package cli // import "miniflux.app/v2/internal/cli"
import (
"sync"
"time"
"miniflux.app/v2/internal/config"
"miniflux.app/v2/internal/logger"
"miniflux.app/v2/internal/model"
feedHandler "miniflux.app/v2/internal/reader/handler"
"miniflux.app/v2/internal/storage"
)
func refreshFeeds(store *storage.Storage) {
var wg sync.WaitGroup
startTime := time.Now()
jobs, err := store.NewBatch(config.Opts.BatchSize())
if err != nil {
logger.Error("[Cronjob] %v", err)
}
nbJobs := len(jobs)
logger.Info("[Cronjob]] Created %d jobs from a batch size of %d", nbJobs, config.Opts.BatchSize())
var jobQueue = make(chan model.Job, nbJobs)
logger.Info("[Cronjob] Starting a pool of %d workers", config.Opts.WorkerPoolSize())
for i := 0; i < config.Opts.WorkerPoolSize(); i++ {
wg.Add(1)
go func(workerID int) {
defer wg.Done()
for job := range jobQueue {
logger.Info("[Cronjob] Refreshing feed #%d for user #%d in worker #%d", job.FeedID, job.UserID, workerID)
if err := feedHandler.RefreshFeed(store, job.UserID, job.FeedID, false); err != nil {
logger.Error("[Cronjob] Refreshing the feed #%d returned this error: %v", job.FeedID, err)
}
}
}(i)
}
for _, job := range jobs {
jobQueue <- job
}
close(jobQueue)
wg.Wait()
logger.Info("[Cronjob] Refreshed %d feed(s) in %s", nbJobs, time.Since(startTime))
}
@@ -1,16 +1,15 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package cli // import "miniflux.app/cli"
package cli // import "miniflux.app/v2/internal/cli"
import (
"fmt"
"os"
"miniflux.app/model"
"miniflux.app/storage"
"miniflux.app/validator"
"miniflux.app/v2/internal/model"
"miniflux.app/v2/internal/storage"
"miniflux.app/v2/internal/validator"
)
func resetPassword(store *storage.Storage) {
+47
View File
@@ -0,0 +1,47 @@
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package cli // import "miniflux.app/v2/internal/cli"
import (
"time"
"miniflux.app/v2/internal/config"
"miniflux.app/v2/internal/logger"
"miniflux.app/v2/internal/storage"
"miniflux.app/v2/internal/worker"
)
func runScheduler(store *storage.Storage, pool *worker.Pool) {
logger.Info(`Starting background scheduler...`)
go feedScheduler(
store,
pool,
config.Opts.PollingFrequency(),
config.Opts.BatchSize(),
)
go cleanupScheduler(
store,
config.Opts.CleanupFrequencyHours(),
)
}
func feedScheduler(store *storage.Storage, pool *worker.Pool, frequency, batchSize int) {
for range time.Tick(time.Duration(frequency) * time.Minute) {
jobs, err := store.NewBatch(batchSize)
logger.Info("[Scheduler:Feed] Pushing %d jobs to the queue", len(jobs))
if err != nil {
logger.Error("[Scheduler:Feed] %v", err)
} else {
pool.Push(jobs)
}
}
}
func cleanupScheduler(store *storage.Storage, frequency int) {
for range time.Tick(time.Duration(frequency) * time.Hour) {
runCleanupTasks(store)
}
}
+7
View File
@@ -0,0 +1,7 @@
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package config // import "miniflux.app/v2/internal/config"
// Opts holds parsed configuration options.
var Opts *Options
@@ -1,8 +1,7 @@
// Copyright 2019 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package config // import "miniflux.app/config"
package config // import "miniflux.app/v2/internal/config"
import (
"os"
@@ -1163,7 +1162,97 @@ func TestPocketConsumerKeyFromUserPrefs(t *testing.T) {
}
}
func TestProxyImages(t *testing.T) {
func TestProxyOption(t *testing.T) {
os.Clearenv()
os.Setenv("PROXY_OPTION", "all")
parser := NewParser()
opts, err := parser.ParseEnvironmentVariables()
if err != nil {
t.Fatalf(`Parsing failure: %v`, err)
}
expected := "all"
result := opts.ProxyOption()
if result != expected {
t.Fatalf(`Unexpected PROXY_OPTION value, got %q instead of %q`, result, expected)
}
}
func TestDefaultProxyOptionValue(t *testing.T) {
os.Clearenv()
parser := NewParser()
opts, err := parser.ParseEnvironmentVariables()
if err != nil {
t.Fatalf(`Parsing failure: %v`, err)
}
expected := defaultProxyOption
result := opts.ProxyOption()
if result != expected {
t.Fatalf(`Unexpected PROXY_OPTION value, got %q instead of %q`, result, expected)
}
}
func TestProxyMediaTypes(t *testing.T) {
os.Clearenv()
os.Setenv("PROXY_MEDIA_TYPES", "image,audio")
parser := NewParser()
opts, err := parser.ParseEnvironmentVariables()
if err != nil {
t.Fatalf(`Parsing failure: %v`, err)
}
expected := []string{"audio", "image"}
if len(expected) != len(opts.ProxyMediaTypes()) {
t.Fatalf(`Unexpected PROXY_MEDIA_TYPES value, got %v instead of %v`, opts.ProxyMediaTypes(), expected)
}
resultMap := make(map[string]bool)
for _, mediaType := range opts.ProxyMediaTypes() {
resultMap[mediaType] = true
}
for _, mediaType := range expected {
if !resultMap[mediaType] {
t.Fatalf(`Unexpected PROXY_MEDIA_TYPES value, got %v instead of %v`, opts.ProxyMediaTypes(), expected)
}
}
}
func TestProxyMediaTypesWithDuplicatedValues(t *testing.T) {
os.Clearenv()
os.Setenv("PROXY_MEDIA_TYPES", "image,audio, image")
parser := NewParser()
opts, err := parser.ParseEnvironmentVariables()
if err != nil {
t.Fatalf(`Parsing failure: %v`, err)
}
expected := []string{"audio", "image"}
if len(expected) != len(opts.ProxyMediaTypes()) {
t.Fatalf(`Unexpected PROXY_MEDIA_TYPES value, got %v instead of %v`, opts.ProxyMediaTypes(), expected)
}
resultMap := make(map[string]bool)
for _, mediaType := range opts.ProxyMediaTypes() {
resultMap[mediaType] = true
}
for _, mediaType := range expected {
if !resultMap[mediaType] {
t.Fatalf(`Unexpected PROXY_MEDIA_TYPES value, got %v instead of %v`, opts.ProxyMediaTypes(), expected)
}
}
}
func TestProxyImagesOptionBackwardCompatibility(t *testing.T) {
os.Clearenv()
os.Setenv("PROXY_IMAGES", "all")
@@ -1173,15 +1262,30 @@ func TestProxyImages(t *testing.T) {
t.Fatalf(`Parsing failure: %v`, err)
}
expected := "all"
result := opts.ProxyImages()
expected := []string{"image"}
if len(expected) != len(opts.ProxyMediaTypes()) {
t.Fatalf(`Unexpected PROXY_MEDIA_TYPES value, got %v instead of %v`, opts.ProxyMediaTypes(), expected)
}
if result != expected {
t.Fatalf(`Unexpected PROXY_IMAGES value, got %q instead of %q`, result, expected)
resultMap := make(map[string]bool)
for _, mediaType := range opts.ProxyMediaTypes() {
resultMap[mediaType] = true
}
for _, mediaType := range expected {
if !resultMap[mediaType] {
t.Fatalf(`Unexpected PROXY_MEDIA_TYPES value, got %v instead of %v`, opts.ProxyMediaTypes(), expected)
}
}
expectedProxyOption := "all"
result := opts.ProxyOption()
if result != expectedProxyOption {
t.Fatalf(`Unexpected PROXY_OPTION value, got %q instead of %q`, result, expectedProxyOption)
}
}
func TestDefaultProxyImagesValue(t *testing.T) {
func TestDefaultProxyMediaTypes(t *testing.T) {
os.Clearenv()
parser := NewParser()
@@ -1190,11 +1294,56 @@ func TestDefaultProxyImagesValue(t *testing.T) {
t.Fatalf(`Parsing failure: %v`, err)
}
expected := defaultProxyImages
result := opts.ProxyImages()
expected := []string{"image"}
if len(expected) != len(opts.ProxyMediaTypes()) {
t.Fatalf(`Unexpected PROXY_MEDIA_TYPES value, got %v instead of %v`, opts.ProxyMediaTypes(), expected)
}
resultMap := make(map[string]bool)
for _, mediaType := range opts.ProxyMediaTypes() {
resultMap[mediaType] = true
}
for _, mediaType := range expected {
if !resultMap[mediaType] {
t.Fatalf(`Unexpected PROXY_MEDIA_TYPES value, got %v instead of %v`, opts.ProxyMediaTypes(), expected)
}
}
}
func TestProxyHTTPClientTimeout(t *testing.T) {
os.Clearenv()
os.Setenv("PROXY_HTTP_CLIENT_TIMEOUT", "24")
parser := NewParser()
opts, err := parser.ParseEnvironmentVariables()
if err != nil {
t.Fatalf(`Parsing failure: %v`, err)
}
expected := 24
result := opts.ProxyHTTPClientTimeout()
if result != expected {
t.Fatalf(`Unexpected PROXY_IMAGES value, got %q instead of %q`, result, expected)
t.Fatalf(`Unexpected PROXY_HTTP_CLIENT_TIMEOUT value, got %d instead of %d`, result, expected)
}
}
func TestDefaultProxyHTTPClientTimeoutValue(t *testing.T) {
os.Clearenv()
parser := NewParser()
opts, err := parser.ParseEnvironmentVariables()
if err != nil {
t.Fatalf(`Parsing failure: %v`, err)
}
expected := defaultProxyHTTPClientTimeout
result := opts.ProxyHTTPClientTimeout()
if result != expected {
t.Fatalf(`Unexpected PROXY_HTTP_CLIENT_TIMEOUT value, got %d instead of %d`, result, expected)
}
}
@@ -1297,6 +1446,41 @@ func TestDefaultHTTPClientMaxBodySizeValue(t *testing.T) {
}
}
func TestHTTPServerTimeout(t *testing.T) {
os.Clearenv()
os.Setenv("HTTP_SERVER_TIMEOUT", "342")
parser := NewParser()
opts, err := parser.ParseEnvironmentVariables()
if err != nil {
t.Fatalf(`Parsing failure: %v`, err)
}
expected := 342
result := opts.HTTPServerTimeout()
if result != expected {
t.Fatalf(`Unexpected HTTP_SERVER_TIMEOUT value, got %d instead of %d`, result, expected)
}
}
func TestDefaultHTTPServerTimeoutValue(t *testing.T) {
os.Clearenv()
parser := NewParser()
opts, err := parser.ParseEnvironmentVariables()
if err != nil {
t.Fatalf(`Parsing failure: %v`, err)
}
expected := defaultHTTPServerTimeout
result := opts.HTTPServerTimeout()
if result != expected {
t.Fatalf(`Unexpected HTTP_SERVER_TIMEOUT value, got %d instead of %d`, result, expected)
}
}
func TestParseConfigFile(t *testing.T) {
content := []byte(`
# This is a comment
@@ -1414,6 +1598,24 @@ func TestAuthProxyUserCreationAdmin(t *testing.T) {
}
}
func TestFetchOdyseeWatchTime(t *testing.T) {
os.Clearenv()
os.Setenv("FETCH_ODYSEE_WATCH_TIME", "1")
parser := NewParser()
opts, err := parser.ParseEnvironmentVariables()
if err != nil {
t.Fatalf(`Parsing failure: %v`, err)
}
expected := true
result := opts.FetchOdyseeWatchTime()
if result != expected {
t.Fatalf(`Unexpected FETCH_ODYSEE_WATCH_TIME value, got %v instead of %v`, result, expected)
}
}
func TestFetchYouTubeWatchTime(t *testing.T) {
os.Clearenv()
os.Setenv("FETCH_YOUTUBE_WATCH_TIME", "1")
@@ -1432,6 +1634,24 @@ func TestFetchYouTubeWatchTime(t *testing.T) {
}
}
func TestYouTubeEmbedUrlOverride(t *testing.T) {
os.Clearenv()
os.Setenv("YOUTUBE_EMBED_URL_OVERRIDE", "https://invidious.custom/embed/")
parser := NewParser()
opts, err := parser.ParseEnvironmentVariables()
if err != nil {
t.Fatalf(`Parsing failure: %v`, err)
}
expected := "https://invidious.custom/embed/"
result := opts.YouTubeEmbedUrlOverride()
if result != expected {
t.Fatalf(`Unexpected YOUTUBE_EMBED_URL_OVERRIDE value, got %v instead of %v`, result, expected)
}
}
func TestParseConfigDumpOutput(t *testing.T) {
os.Clearenv()
+100 -18
View File
@@ -1,16 +1,16 @@
// Copyright 2019 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package config // import "miniflux.app/config"
package config // import "miniflux.app/v2/internal/config"
import (
"crypto/rand"
"fmt"
"sort"
"strings"
"time"
"miniflux.app/version"
"miniflux.app/v2/internal/version"
)
const (
@@ -45,8 +45,13 @@ const (
defaultCleanupArchiveUnreadDays = 180
defaultCleanupArchiveBatchSize = 10000
defaultCleanupRemoveSessionsDays = 30
defaultProxyImages = "http-only"
defaultProxyHTTPClientTimeout = 120
defaultProxyOption = "http-only"
defaultProxyMediaTypes = "image"
defaultProxyUrl = ""
defaultFetchOdyseeWatchTime = false
defaultFetchYouTubeWatchTime = false
defaultYouTubeEmbedUrlOverride = "https://www.youtube-nocookie.com/embed/"
defaultCreateAdmin = false
defaultAdminUsername = ""
defaultAdminPassword = ""
@@ -60,6 +65,7 @@ const (
defaultHTTPClientTimeout = 20
defaultHTTPClientMaxBodySize = 15
defaultHTTPClientProxy = ""
defaultHTTPServerTimeout = 300
defaultAuthProxyHeader = ""
defaultAuthProxyUserCreation = false
defaultMaintenanceMode = false
@@ -67,6 +73,8 @@ const (
defaultMetricsCollector = false
defaultMetricsRefreshInterval = 60
defaultMetricsAllowedNetworks = "127.0.0.1/8"
defaultMetricsUsername = ""
defaultMetricsPassword = ""
defaultWatchdog = true
defaultInvidiousInstance = "yewtu.be"
)
@@ -115,8 +123,13 @@ type Options struct {
createAdmin bool
adminUsername string
adminPassword string
proxyImages string
proxyHTTPClientTimeout int
proxyOption string
proxyMediaTypes []string
proxyUrl string
fetchOdyseeWatchTime bool
fetchYouTubeWatchTime bool
youTubeEmbedUrlOverride string
oauth2UserCreationAllowed bool
oauth2ClientID string
oauth2ClientSecret string
@@ -128,6 +141,7 @@ type Options struct {
httpClientMaxBodySize int64
httpClientProxy string
httpClientUserAgent string
httpServerTimeout int
authProxyHeader string
authProxyUserCreation bool
maintenanceMode bool
@@ -135,12 +149,18 @@ type Options struct {
metricsCollector bool
metricsRefreshInterval int
metricsAllowedNetworks []string
metricsUsername string
metricsPassword string
watchdog bool
invidiousInstance string
proxyPrivateKey []byte
}
// NewOptions returns Options with default values.
func NewOptions() *Options {
randomKey := make([]byte, 16)
rand.Read(randomKey)
return &Options{
HTTPS: defaultHTTPS,
logDateTime: defaultLogDateTime,
@@ -174,8 +194,13 @@ func NewOptions() *Options {
pollingParsingErrorLimit: defaultPollingParsingErrorLimit,
workerPoolSize: defaultWorkerPoolSize,
createAdmin: defaultCreateAdmin,
proxyImages: defaultProxyImages,
proxyHTTPClientTimeout: defaultProxyHTTPClientTimeout,
proxyOption: defaultProxyOption,
proxyMediaTypes: []string{defaultProxyMediaTypes},
proxyUrl: defaultProxyUrl,
fetchOdyseeWatchTime: defaultFetchOdyseeWatchTime,
fetchYouTubeWatchTime: defaultFetchYouTubeWatchTime,
youTubeEmbedUrlOverride: defaultYouTubeEmbedUrlOverride,
oauth2UserCreationAllowed: defaultOAuth2UserCreation,
oauth2ClientID: defaultOAuth2ClientID,
oauth2ClientSecret: defaultOAuth2ClientSecret,
@@ -187,6 +212,7 @@ func NewOptions() *Options {
httpClientMaxBodySize: defaultHTTPClientMaxBodySize * 1024 * 1024,
httpClientProxy: defaultHTTPClientProxy,
httpClientUserAgent: defaultHTTPClientUserAgent,
httpServerTimeout: defaultHTTPServerTimeout,
authProxyHeader: defaultAuthProxyHeader,
authProxyUserCreation: defaultAuthProxyUserCreation,
maintenanceMode: defaultMaintenanceMode,
@@ -194,8 +220,11 @@ func NewOptions() *Options {
metricsCollector: defaultMetricsCollector,
metricsRefreshInterval: defaultMetricsRefreshInterval,
metricsAllowedNetworks: []string{defaultMetricsAllowedNetworks},
metricsUsername: defaultMetricsUsername,
metricsPassword: defaultMetricsPassword,
watchdog: defaultWatchdog,
invidiousInstance: defaultInvidiousInstance,
proxyPrivateKey: randomKey,
}
}
@@ -405,9 +434,35 @@ func (o *Options) FetchYouTubeWatchTime() bool {
return o.fetchYouTubeWatchTime
}
// ProxyImages returns "none" to never proxy, "http-only" to proxy non-HTTPS, "all" to always proxy.
func (o *Options) ProxyImages() string {
return o.proxyImages
// YouTubeEmbedUrlOverride returns YouTube URL which will be used for embeds
func (o *Options) YouTubeEmbedUrlOverride() string {
return o.youTubeEmbedUrlOverride
}
// FetchOdyseeWatchTime returns true if the Odysee video duration
// should be fetched and used as a reading time.
func (o *Options) FetchOdyseeWatchTime() bool {
return o.fetchOdyseeWatchTime
}
// ProxyOption returns "none" to never proxy, "http-only" to proxy non-HTTPS, "all" to always proxy.
func (o *Options) ProxyOption() string {
return o.proxyOption
}
// ProxyMediaTypes returns a slice of media types to proxy.
func (o *Options) ProxyMediaTypes() []string {
return o.proxyMediaTypes
}
// ProxyUrl returns a string of a URL to use to proxy image requests
func (o *Options) ProxyUrl() string {
return o.proxyUrl
}
// ProxyHTTPClientTimeout returns the time limit in seconds before the proxy HTTP client cancel the request.
func (o *Options) ProxyHTTPClientTimeout() int {
return o.proxyHTTPClientTimeout
}
// HasHTTPService returns true if the HTTP service is enabled.
@@ -443,6 +498,11 @@ func (o *Options) HTTPClientProxy() string {
return o.httpClientProxy
}
// HTTPServerTimeout returns the time limit in seconds before the HTTP server cancel the request.
func (o *Options) HTTPServerTimeout() int {
return o.httpServerTimeout
}
// HasHTTPClientProxyConfigured returns true if the HTTP proxy is configured.
func (o *Options) HasHTTPClientProxyConfigured() bool {
return o.httpClientProxy != ""
@@ -475,6 +535,14 @@ func (o *Options) MetricsAllowedNetworks() []string {
return o.metricsAllowedNetworks
}
func (o *Options) MetricsUsername() string {
return o.metricsUsername
}
func (o *Options) MetricsPassword() string {
return o.metricsPassword
}
// HTTPClientUserAgent returns the global User-Agent header for miniflux.
func (o *Options) HTTPClientUserAgent() string {
return o.httpClientUserAgent
@@ -490,6 +558,11 @@ func (o *Options) InvidiousInstance() string {
return o.invidiousInstance
}
// ProxyPrivateKey returns the private key used by the media proxy
func (o *Options) ProxyPrivateKey() []byte {
return o.proxyPrivateKey
}
// SortedOptions returns options as a list of key value pairs, sorted by keys.
func (o *Options) SortedOptions(redactSecret bool) []*Option {
var keyValues = map[string]interface{}{
@@ -502,36 +575,40 @@ func (o *Options) SortedOptions(redactSecret bool) []*Option {
"BATCH_SIZE": o.batchSize,
"CERT_DOMAIN": o.certDomain,
"CERT_FILE": o.certFile,
"CLEANUP_ARCHIVE_BATCH_SIZE": o.cleanupArchiveBatchSize,
"CLEANUP_ARCHIVE_READ_DAYS": o.cleanupArchiveReadDays,
"CLEANUP_ARCHIVE_UNREAD_DAYS": o.cleanupArchiveUnreadDays,
"CLEANUP_ARCHIVE_BATCH_SIZE": o.cleanupArchiveBatchSize,
"CLEANUP_FREQUENCY_HOURS": o.cleanupFrequencyHours,
"CLEANUP_REMOVE_SESSIONS_DAYS": o.cleanupRemoveSessionsDays,
"CREATE_ADMIN": o.createAdmin,
"DATABASE_CONNECTION_LIFETIME": o.databaseConnectionLifetime,
"DATABASE_MAX_CONNS": o.databaseMaxConns,
"DATABASE_MIN_CONNS": o.databaseMinConns,
"DATABASE_CONNECTION_LIFETIME": o.databaseConnectionLifetime,
"DATABASE_URL": redactSecretValue(o.databaseURL, redactSecret),
"DEBUG": o.debug,
"DISABLE_HSTS": !o.hsts,
"DISABLE_SCHEDULER_SERVICE": !o.schedulerService,
"DISABLE_HTTP_SERVICE": !o.httpService,
"DISABLE_SCHEDULER_SERVICE": !o.schedulerService,
"FETCH_YOUTUBE_WATCH_TIME": o.fetchYouTubeWatchTime,
"FETCH_ODYSEE_WATCH_TIME": o.fetchOdyseeWatchTime,
"HTTPS": o.HTTPS,
"HTTP_CLIENT_MAX_BODY_SIZE": o.httpClientMaxBodySize,
"HTTP_CLIENT_PROXY": o.httpClientProxy,
"HTTP_CLIENT_TIMEOUT": o.httpClientTimeout,
"HTTP_CLIENT_USER_AGENT": o.httpClientUserAgent,
"HTTP_SERVER_TIMEOUT": o.httpServerTimeout,
"HTTP_SERVICE": o.httpService,
"KEY_FILE": o.certKeyFile,
"INVIDIOUS_INSTANCE": o.invidiousInstance,
"KEY_FILE": o.certKeyFile,
"LISTEN_ADDR": o.listenAddr,
"LOG_DATE_TIME": o.logDateTime,
"MAINTENANCE_MESSAGE": o.maintenanceMessage,
"MAINTENANCE_MODE": o.maintenanceMode,
"METRICS_ALLOWED_NETWORKS": strings.Join(o.metricsAllowedNetworks, ","),
"METRICS_COLLECTOR": o.metricsCollector,
"METRICS_PASSWORD": redactSecretValue(o.metricsPassword, redactSecret),
"METRICS_REFRESH_INTERVAL": o.metricsRefreshInterval,
"METRICS_USERNAME": o.metricsUsername,
"OAUTH2_CLIENT_ID": o.oauth2ClientID,
"OAUTH2_CLIENT_SECRET": redactSecretValue(o.oauth2ClientSecret, redactSecret),
"OAUTH2_OIDC_DISCOVERY_ENDPOINT": o.oauth2OidcDiscoveryEndpoint,
@@ -542,15 +619,20 @@ func (o *Options) SortedOptions(redactSecret bool) []*Option {
"POLLING_FREQUENCY": o.pollingFrequency,
"POLLING_PARSING_ERROR_LIMIT": o.pollingParsingErrorLimit,
"POLLING_SCHEDULER": o.pollingScheduler,
"PROXY_IMAGES": o.proxyImages,
"PROXY_HTTP_CLIENT_TIMEOUT": o.proxyHTTPClientTimeout,
"PROXY_MEDIA_TYPES": o.proxyMediaTypes,
"PROXY_OPTION": o.proxyOption,
"PROXY_PRIVATE_KEY": redactSecretValue(string(o.proxyPrivateKey), redactSecret),
"PROXY_URL": o.proxyUrl,
"ROOT_URL": o.rootURL,
"RUN_MIGRATIONS": o.runMigrations,
"SCHEDULER_ENTRY_FREQUENCY_MAX_INTERVAL": o.schedulerEntryFrequencyMaxInterval,
"SCHEDULER_ENTRY_FREQUENCY_MIN_INTERVAL": o.schedulerEntryFrequencyMinInterval,
"SCHEDULER_SERVICE": o.schedulerService,
"SERVER_TIMING_HEADER": o.serverTimingHeader,
"WORKER_POOL_SIZE": o.workerPoolSize,
"WATCHDOG": o.watchdog,
"WORKER_POOL_SIZE": o.workerPoolSize,
"YOUTUBE_EMBED_URL_OVERRIDE": o.youTubeEmbedUrlOverride,
}
keys := make([]string, 0, len(keyValues))
@@ -578,7 +660,7 @@ func (o *Options) String() string {
func redactSecretValue(value string, redactSecret bool) string {
if redactSecret && value != "" {
return "******"
return "<secret>"
}
return value
}
+51 -6
View File
@@ -1,12 +1,12 @@
// Copyright 2019 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package config // import "miniflux.app/config"
package config // import "miniflux.app/v2/internal/config"
import (
"bufio"
"bytes"
"crypto/rand"
"errors"
"fmt"
"io"
@@ -137,8 +137,20 @@ func (p *Parser) parseLines(lines []string) (err error) {
p.opts.schedulerEntryFrequencyMinInterval = parseInt(value, defaultSchedulerEntryFrequencyMinInterval)
case "POLLING_PARSING_ERROR_LIMIT":
p.opts.pollingParsingErrorLimit = parseInt(value, defaultPollingParsingErrorLimit)
// kept for compatibility purpose
case "PROXY_IMAGES":
p.opts.proxyImages = parseString(value, defaultProxyImages)
p.opts.proxyOption = parseString(value, defaultProxyOption)
case "PROXY_HTTP_CLIENT_TIMEOUT":
p.opts.proxyHTTPClientTimeout = parseInt(value, defaultProxyHTTPClientTimeout)
case "PROXY_OPTION":
p.opts.proxyOption = parseString(value, defaultProxyOption)
case "PROXY_MEDIA_TYPES":
p.opts.proxyMediaTypes = parseStringList(value, []string{defaultProxyMediaTypes})
// kept for compatibility purpose
case "PROXY_IMAGE_URL":
p.opts.proxyUrl = parseString(value, defaultProxyUrl)
case "PROXY_URL":
p.opts.proxyUrl = parseString(value, defaultProxyUrl)
case "CREATE_ADMIN":
p.opts.createAdmin = parseBool(value, defaultCreateAdmin)
case "ADMIN_USERNAME":
@@ -177,6 +189,8 @@ func (p *Parser) parseLines(lines []string) (err error) {
p.opts.httpClientProxy = parseString(value, defaultHTTPClientProxy)
case "HTTP_CLIENT_USER_AGENT":
p.opts.httpClientUserAgent = parseString(value, defaultHTTPClientUserAgent)
case "HTTP_SERVER_TIMEOUT":
p.opts.httpServerTimeout = parseInt(value, defaultHTTPServerTimeout)
case "AUTH_PROXY_HEADER":
p.opts.authProxyHeader = parseString(value, defaultAuthProxyHeader)
case "AUTH_PROXY_USER_CREATION":
@@ -191,12 +205,28 @@ func (p *Parser) parseLines(lines []string) (err error) {
p.opts.metricsRefreshInterval = parseInt(value, defaultMetricsRefreshInterval)
case "METRICS_ALLOWED_NETWORKS":
p.opts.metricsAllowedNetworks = parseStringList(value, []string{defaultMetricsAllowedNetworks})
case "METRICS_USERNAME":
p.opts.metricsUsername = parseString(value, defaultMetricsUsername)
case "METRICS_USERNAME_FILE":
p.opts.metricsUsername = readSecretFile(value, defaultMetricsUsername)
case "METRICS_PASSWORD":
p.opts.metricsPassword = parseString(value, defaultMetricsPassword)
case "METRICS_PASSWORD_FILE":
p.opts.metricsPassword = readSecretFile(value, defaultMetricsPassword)
case "FETCH_ODYSEE_WATCH_TIME":
p.opts.fetchOdyseeWatchTime = parseBool(value, defaultFetchOdyseeWatchTime)
case "FETCH_YOUTUBE_WATCH_TIME":
p.opts.fetchYouTubeWatchTime = parseBool(value, defaultFetchYouTubeWatchTime)
case "YOUTUBE_EMBED_URL_OVERRIDE":
p.opts.youTubeEmbedUrlOverride = parseString(value, defaultYouTubeEmbedUrlOverride)
case "WATCHDOG":
p.opts.watchdog = parseBool(value, defaultWatchdog)
case "INVIDIOUS_INSTANCE":
p.opts.invidiousInstance = parseString(value, defaultInvidiousInstance)
case "PROXY_PRIVATE_KEY":
randomKey := make([]byte, 16)
rand.Read(randomKey)
p.opts.proxyPrivateKey = parseBytes(value, randomKey)
}
}
@@ -269,14 +299,29 @@ func parseStringList(value string, fallback []string) []string {
}
var strList []string
strMap := make(map[string]bool)
items := strings.Split(value, ",")
for _, item := range items {
strList = append(strList, strings.TrimSpace(item))
itemValue := strings.TrimSpace(item)
if _, found := strMap[itemValue]; !found {
strMap[itemValue] = true
strList = append(strList, itemValue)
}
}
return strList
}
func parseBytes(value string, fallback []byte) []byte {
if value == "" {
return fallback
}
return []byte(value)
}
func readSecretFile(filename, fallback string) string {
data, err := os.ReadFile(filename)
if err != nil {
@@ -1,8 +1,7 @@
// Copyright 2019 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package config // import "miniflux.app/config"
package config // import "miniflux.app/v2/internal/config"
import (
"testing"
+10 -4
View File
@@ -1,8 +1,7 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package crypto // import "miniflux.app/crypto"
package crypto // import "miniflux.app/v2/internal/crypto"
import (
"crypto/rand"
@@ -10,6 +9,8 @@ import (
"encoding/base64"
"encoding/hex"
"fmt"
"golang.org/x/crypto/bcrypt"
)
// HashFromBytes returns a SHA-256 checksum of the input.
@@ -42,3 +43,8 @@ func GenerateRandomString(size int) string {
func GenerateRandomStringHex(size int) string {
return hex.EncodeToString(GenerateRandomBytes(size))
}
func HashPassword(password string) (string, error) {
bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
return string(bytes), err
}
@@ -1,8 +1,7 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package database // import "miniflux.app/database"
package database // import "miniflux.app/v2/internal/database"
import (
"database/sql"
@@ -1,8 +1,7 @@
// Copyright 2020 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package database // import "miniflux.app/database"
package database // import "miniflux.app/v2/internal/database"
import (
"database/sql"
@@ -591,4 +590,166 @@ var migrations = []func(tx *sql.Tx) error{
_, err = tx.Exec(sql)
return err
},
func(tx *sql.Tx) (err error) {
_, err = tx.Exec(`
ALTER TABLE feeds ADD COLUMN url_rewrite_rules text not null default ''
`)
return err
},
func(tx *sql.Tx) (err error) {
_, err = tx.Exec(`
ALTER TABLE users ADD COLUMN default_reading_speed int default 265;
ALTER TABLE users ADD COLUMN cjk_reading_speed int default 500;
`)
return
},
func(tx *sql.Tx) (err error) {
_, err = tx.Exec(`
ALTER TABLE users ADD COLUMN default_home_page text default 'unread';
`)
return
},
func(tx *sql.Tx) (err error) {
_, err = tx.Exec(`
ALTER TABLE integrations ADD COLUMN wallabag_only_url bool default 'f';
`)
return
},
func(tx *sql.Tx) (err error) {
_, err = tx.Exec(`
ALTER TABLE users ADD COLUMN categories_sorting_order text not null default 'unread_count';
`)
return
},
func(tx *sql.Tx) (err error) {
sql := `
ALTER TABLE integrations ADD COLUMN matrix_bot_enabled bool default 'f';
ALTER TABLE integrations ADD COLUMN matrix_bot_user text default '';
ALTER TABLE integrations ADD COLUMN matrix_bot_password text default '';
ALTER TABLE integrations ADD COLUMN matrix_bot_url text default '';
ALTER TABLE integrations ADD COLUMN matrix_bot_chat_id text default '';
`
_, err = tx.Exec(sql)
return
},
func(tx *sql.Tx) (err error) {
sql := `ALTER TABLE users ADD COLUMN double_tap boolean default 't'`
_, err = tx.Exec(sql)
return err
},
func(tx *sql.Tx) (err error) {
_, err = tx.Exec(`
ALTER TABLE entries ADD COLUMN tags text[] default '{}';
`)
return
},
func(tx *sql.Tx) (err error) {
sql := `
ALTER TABLE users RENAME double_tap TO gesture_nav;
ALTER TABLE users ALTER COLUMN gesture_nav SET DATA TYPE text using case when gesture_nav = true then 'tap' when gesture_nav = false then 'none' end;
ALTER TABLE users ALTER COLUMN gesture_nav SET default 'tap';
`
_, err = tx.Exec(sql)
return err
},
func(tx *sql.Tx) (err error) {
sql := `
ALTER TABLE integrations ADD COLUMN linkding_tags text default '';
`
_, err = tx.Exec(sql)
return err
},
func(tx *sql.Tx) (err error) {
sql := `
ALTER TABLE feeds ADD COLUMN no_media_player boolean default 'f';
ALTER TABLE enclosures ADD COLUMN media_progression int default 0;
`
_, err = tx.Exec(sql)
return err
},
func(tx *sql.Tx) (err error) {
sql := `
ALTER TABLE integrations ADD COLUMN linkding_mark_as_unread bool default 'f';
`
_, err = tx.Exec(sql)
return err
},
func(tx *sql.Tx) (err error) {
// Delete duplicated rows
sql := `
DELETE FROM enclosures a USING enclosures b
WHERE a.id < b.id
AND a.user_id = b.user_id
AND a.entry_id = b.entry_id
AND a.url = b.url;
`
_, err = tx.Exec(sql)
if err != nil {
return err
}
// Remove previous index
_, err = tx.Exec(`DROP INDEX enclosures_user_entry_url_idx`)
if err != nil {
return err
}
// Create unique index
_, err = tx.Exec(`CREATE UNIQUE INDEX enclosures_user_entry_url_unique_idx ON enclosures(user_id, entry_id, md5(url))`)
if err != nil {
return err
}
return nil
},
func(tx *sql.Tx) (err error) {
sql := `ALTER TABLE users ADD COLUMN mark_read_on_view boolean default 't'`
_, err = tx.Exec(sql)
return err
},
func(tx *sql.Tx) (err error) {
sql := `
ALTER TABLE integrations ADD COLUMN notion_enabled bool default 'f';
ALTER TABLE integrations ADD COLUMN notion_token text default '';
ALTER TABLE integrations ADD COLUMN notion_page_id text default '';
`
_, err = tx.Exec(sql)
return err
},
func(tx *sql.Tx) (err error) {
sql := `
ALTER TABLE integrations ADD COLUMN readwise_enabled bool default 'f';
ALTER TABLE integrations ADD COLUMN readwise_api_key text default '';
`
_, err = tx.Exec(sql)
return err
},
func(tx *sql.Tx) (err error) {
sql := `
ALTER TABLE integrations ADD COLUMN apprise_enabled bool default 'f';
ALTER TABLE integrations ADD COLUMN apprise_url text default '';
ALTER TABLE integrations ADD COLUMN apprise_services_url text default '';
`
_, err = tx.Exec(sql)
return err
},
func(tx *sql.Tx) (err error) {
sql := `
ALTER TABLE integrations ADD COLUMN shiori_enabled bool default 'f';
ALTER TABLE integrations ADD COLUMN shiori_url text default '';
ALTER TABLE integrations ADD COLUMN shiori_username text default '';
ALTER TABLE integrations ADD COLUMN shiori_password text default '';
`
_, err = tx.Exec(sql)
return err
},
func(tx *sql.Tx) (err error) {
sql := `
ALTER TABLE integrations ADD COLUMN shaarli_enabled bool default 'f';
ALTER TABLE integrations ADD COLUMN shaarli_url text default '';
ALTER TABLE integrations ADD COLUMN shaarli_api_secret text default '';
`
_, err = tx.Exec(sql)
return err
},
}
@@ -1,13 +1,12 @@
// Copyright 2017 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package errors // import "miniflux.app/errors"
package errors // import "miniflux.app/v2/internal/errors"
import (
"fmt"
"miniflux.app/locale"
"miniflux.app/v2/internal/locale"
)
// LocalizedError represents an error than could be translated to another language.
+59 -61
View File
@@ -1,8 +1,7 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package fever // import "miniflux.app/fever"
package fever // import "miniflux.app/v2/internal/fever"
import (
"net/http"
@@ -10,19 +9,20 @@ import (
"strings"
"time"
"miniflux.app/http/request"
"miniflux.app/http/response/json"
"miniflux.app/integration"
"miniflux.app/logger"
"miniflux.app/model"
"miniflux.app/storage"
"miniflux.app/v2/internal/http/request"
"miniflux.app/v2/internal/http/response/json"
"miniflux.app/v2/internal/integration"
"miniflux.app/v2/internal/logger"
"miniflux.app/v2/internal/model"
"miniflux.app/v2/internal/proxy"
"miniflux.app/v2/internal/storage"
"github.com/gorilla/mux"
)
// Serve handles Fever API calls.
func Serve(router *mux.Router, store *storage.Storage) {
handler := &handler{store}
handler := &handler{store, router}
sr := router.PathPrefix("/fever").Subrouter()
sr.Use(newMiddleware(store).serve)
@@ -30,7 +30,8 @@ func Serve(router *mux.Router, store *storage.Storage) {
}
type handler struct {
store *storage.Storage
store *storage.Storage
router *mux.Router
}
func (h *handler) serve(w http.ResponseWriter, r *http.Request) {
@@ -61,13 +62,13 @@ func (h *handler) serve(w http.ResponseWriter, r *http.Request) {
/*
A request with the groups argument will return two additional members:
groups contains an array of group objects
feeds_groups contains an array of feeds_group objects
groups contains an array of group objects
feeds_groups contains an array of feeds_group objects
A group object has the following members:
id (positive integer)
title (utf-8 string)
id (positive integer)
title (utf-8 string)
The feeds_group object is documented under Feeds/Groups Relationships.
@@ -76,7 +77,6 @@ an is_spark equal to 0.
The Sparks super group is not included in this response and is composed of all feeds with an
is_spark equal to 1.
*/
func (h *handler) handleGroups(w http.ResponseWriter, r *http.Request) {
userID := request.UserID(r)
@@ -107,18 +107,18 @@ func (h *handler) handleGroups(w http.ResponseWriter, r *http.Request) {
/*
A request with the feeds argument will return two additional members:
feeds contains an array of group objects
feeds_groups contains an array of feeds_group objects
feeds contains an array of group objects
feeds_groups contains an array of feeds_group objects
A feed object has the following members:
id (positive integer)
favicon_id (positive integer)
title (utf-8 string)
url (utf-8 string)
site_url (utf-8 string)
is_spark (boolean integer)
last_updated_on_time (Unix timestamp/integer)
id (positive integer)
favicon_id (positive integer)
title (utf-8 string)
url (utf-8 string)
site_url (utf-8 string)
is_spark (boolean integer)
last_updated_on_time (Unix timestamp/integer)
The feeds_group object is documented under Feeds/Groups Relationships.
@@ -165,12 +165,12 @@ func (h *handler) handleFeeds(w http.ResponseWriter, r *http.Request) {
/*
A request with the favicons argument will return one additional member:
favicons contains an array of favicon objects
favicons contains an array of favicon objects
A favicon object has the following members:
id (positive integer)
data (base64 encoded image data; prefixed by image type)
id (positive integer)
data (base64 encoded image data; prefixed by image type)
An example data value:
@@ -206,20 +206,20 @@ func (h *handler) handleFavicons(w http.ResponseWriter, r *http.Request) {
/*
A request with the items argument will return two additional members:
items contains an array of item objects
total_items contains the total number of items stored in the database (added in API version 2)
items contains an array of item objects
total_items contains the total number of items stored in the database (added in API version 2)
An item object has the following members:
id (positive integer)
feed_id (positive integer)
title (utf-8 string)
author (utf-8 string)
html (utf-8 string)
url (utf-8 string)
is_saved (boolean integer)
is_read (boolean integer)
created_on_time (Unix timestamp/integer)
id (positive integer)
feed_id (positive integer)
title (utf-8 string)
author (utf-8 string)
html (utf-8 string)
url (utf-8 string)
is_saved (boolean integer)
is_read (boolean integer)
created_on_time (Unix timestamp/integer)
Most servers wont have enough memory allocated to PHP to dump all items at once.
Three optional arguments control determine the items included in the response.
@@ -232,7 +232,6 @@ Three optional arguments control determine the items included in the response.
Use the with_ids argument with a comma-separated list of item ids to request (a maximum of 50) specific items.
(added in API version 2)
*/
func (h *handler) handleItems(w http.ResponseWriter, r *http.Request) {
var result itemsResponse
@@ -242,8 +241,7 @@ func (h *handler) handleItems(w http.ResponseWriter, r *http.Request) {
builder := h.store.NewEntryQueryBuilder(userID)
builder.WithoutStatus(model.EntryStatusRemoved)
builder.WithLimit(50)
builder.WithOrder("id")
builder.WithDirection(model.DefaultSortingDirection)
builder.WithSorting("id", model.DefaultSortingDirection)
switch {
case request.HasQueryParam(r, "since_id"):
@@ -256,11 +254,11 @@ func (h *handler) handleItems(w http.ResponseWriter, r *http.Request) {
maxID := request.QueryInt64Param(r, "max_id", 0)
if maxID == 0 {
logger.Debug("[Fever] Fetching most recent items for user #%d", userID)
builder.WithDirection("desc")
builder.WithSorting("id", "DESC")
} else if maxID > 0 {
logger.Debug("[Fever] Fetching items before #%d for user #%d", maxID, userID)
builder.BeforeEntryID(maxID)
builder.WithDirection("desc")
builder.WithSorting("id", "DESC")
}
case request.HasQueryParam(r, "with_ids"):
csvItemIDs := request.QueryStringParam(r, "with_ids", "")
@@ -310,7 +308,7 @@ func (h *handler) handleItems(w http.ResponseWriter, r *http.Request) {
FeedID: entry.FeedID,
Title: entry.Title,
Author: entry.Author,
HTML: entry.Content,
HTML: proxy.AbsoluteProxyRewriter(h.router, r.Host, entry.Content),
URL: entry.URL,
IsSaved: isSaved,
IsRead: isRead,
@@ -327,7 +325,8 @@ The unread_item_ids and saved_item_ids arguments can be used to keep your local
with the remote Fever installation.
A request with the unread_item_ids argument will return one additional member:
unread_item_ids (string/comma-separated list of positive integers)
unread_item_ids (string/comma-separated list of positive integers)
*/
func (h *handler) handleUnreadItems(w http.ResponseWriter, r *http.Request) {
userID := request.UserID(r)
@@ -384,9 +383,9 @@ func (h *handler) handleSavedItems(w http.ResponseWriter, r *http.Request) {
}
/*
mark=item
as=? where ? is replaced with read, saved or unsaved
id=? where ? is replaced with the id of the item to modify
mark=item
as=? where ? is replaced with read, saved or unsaved
id=? where ? is replaced with the id of the item to modify
*/
func (h *handler) handleWriteItems(w http.ResponseWriter, r *http.Request) {
userID := request.UserID(r)
@@ -448,10 +447,10 @@ func (h *handler) handleWriteItems(w http.ResponseWriter, r *http.Request) {
}
/*
mark=feed
as=read
id=? where ? is replaced with the id of the feed or group to modify
before=? where ? is replaced with the Unix timestamp of the the local clients most recent items API request
mark=feed
as=read
id=? where ? is replaced with the id of the feed or group to modify
before=? where ? is replaced with the Unix timestamp of the the local clients most recent items API request
*/
func (h *handler) handleWriteFeeds(w http.ResponseWriter, r *http.Request) {
userID := request.UserID(r)
@@ -474,10 +473,10 @@ func (h *handler) handleWriteFeeds(w http.ResponseWriter, r *http.Request) {
}
/*
mark=group
as=read
id=? where ? is replaced with the id of the feed or group to modify
before=? where ? is replaced with the Unix timestamp of the the local clients most recent items API request
mark=group
as=read
id=? where ? is replaced with the id of the feed or group to modify
before=? where ? is replaced with the Unix timestamp of the the local clients most recent items API request
*/
func (h *handler) handleWriteGroups(w http.ResponseWriter, r *http.Request) {
userID := request.UserID(r)
@@ -510,9 +509,8 @@ func (h *handler) handleWriteGroups(w http.ResponseWriter, r *http.Request) {
/*
A feeds_group object has the following members:
group_id (positive integer)
feed_ids (string/comma-separated list of positive integers)
group_id (positive integer)
feed_ids (string/comma-separated list of positive integers)
*/
func (h *handler) buildFeedGroups(feeds model.Feeds) []feedsGroups {
feedsGroupedByCategory := make(map[int64][]string)
@@ -1,17 +1,16 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package fever // import "miniflux.app/fever"
package fever // import "miniflux.app/v2/internal/fever"
import (
"context"
"net/http"
"miniflux.app/http/request"
"miniflux.app/http/response/json"
"miniflux.app/logger"
"miniflux.app/storage"
"miniflux.app/v2/internal/http/request"
"miniflux.app/v2/internal/http/response/json"
"miniflux.app/v2/internal/logger"
"miniflux.app/v2/internal/storage"
)
type middleware struct {
@@ -1,8 +1,7 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package fever // import "miniflux.app/fever"
package fever // import "miniflux.app/v2/internal/fever"
import (
"time"
@@ -23,8 +22,8 @@ func (b *baseResponse) SetCommonValues() {
/*
The default response is a JSON object containing two members:
api_version contains the version of the API responding (positive integer)
auth whether the request was successfully authenticated (boolean integer)
api_version contains the version of the API responding (positive integer)
auth whether the request was successfully authenticated (boolean integer)
The API can also return XML by passing xml as the optional value of the api argument like so:
@@ -37,7 +36,6 @@ at least one additional member:
last_refreshed_on_time contains the time of the most recently refreshed (not updated)
feed (Unix timestamp/integer)
*/
func newBaseResponse() baseResponse {
r := baseResponse{}
@@ -1,8 +1,7 @@
// Copyright 2022 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package googlereader // import "miniflux.app/googlereader"
package googlereader // import "miniflux.app/v2/internal/googlereader"
import (
"errors"
@@ -14,17 +13,19 @@ import (
"time"
"github.com/gorilla/mux"
"miniflux.app/config"
"miniflux.app/http/request"
"miniflux.app/http/response/json"
"miniflux.app/http/route"
"miniflux.app/integration"
"miniflux.app/logger"
"miniflux.app/model"
mff "miniflux.app/reader/handler"
mfs "miniflux.app/reader/subscription"
"miniflux.app/storage"
"miniflux.app/validator"
"miniflux.app/v2/internal/config"
"miniflux.app/v2/internal/http/request"
"miniflux.app/v2/internal/http/response/json"
"miniflux.app/v2/internal/http/route"
"miniflux.app/v2/internal/integration"
"miniflux.app/v2/internal/logger"
"miniflux.app/v2/internal/model"
"miniflux.app/v2/internal/proxy"
mff "miniflux.app/v2/internal/reader/handler"
mfs "miniflux.app/v2/internal/reader/subscription"
"miniflux.app/v2/internal/storage"
"miniflux.app/v2/internal/urllib"
"miniflux.app/v2/internal/validator"
)
type handler struct {
@@ -88,8 +89,10 @@ const (
ParamTitle = "t"
// ParamQuickAdd - name of the parameter for a URL being quick subscribed to
ParamQuickAdd = "quickadd"
// ParamDestination - name fo the parameter for the new name of a tag
// ParamDestination - name of the parameter for the new name of a tag
ParamDestination = "dest"
// ParamContinuation - name of the parameter for callers to pass to receive the next page of results
ParamContinuation = "c"
)
// StreamType represents the possible stream types
@@ -130,6 +133,7 @@ type RequestModifiers struct {
FilterTargets []Stream
Streams []Stream
Count int
Offset int
SortDirection string
StartTime int64
StopTime int64
@@ -185,6 +189,7 @@ func (r RequestModifiers) String() string {
result += fmt.Sprintf(" %v\n", s)
}
result += fmt.Sprintf("Count: %d\n", r.Count)
result += fmt.Sprintf("Offset: %d\n", r.Offset)
result += fmt.Sprintf("Sort Direction: %s\n", r.SortDirection)
result += fmt.Sprintf("Continuation Token: %s\n", r.ContinuationToken)
result += fmt.Sprintf("Start Time: %d\n", r.StartTime)
@@ -243,8 +248,9 @@ func getStreamFilterModifiers(r *http.Request) (RequestModifiers, error) {
}
result.Count = request.QueryIntParam(r, ParamStreamMaxItems, 0)
result.StartTime = int64(request.QueryIntParam(r, ParamStreamStartTime, 0))
result.StopTime = int64(request.QueryIntParam(r, ParamStreamStopTime, 0))
result.Offset = request.QueryIntParam(r, ParamContinuation, 0)
result.StartTime = request.QueryInt64Param(r, ParamStreamStartTime, int64(0))
result.StopTime = request.QueryInt64Param(r, ParamStreamStopTime, int64(0))
return result, nil
}
@@ -783,8 +789,7 @@ func (h *handler) streamItemContents(w http.ResponseWriter, r *http.Request) {
builder := h.store.NewEntryQueryBuilder(userID)
builder.WithoutStatus(model.EntryStatusRemoved)
builder.WithEntryIDs(itemIDs)
builder.WithOrder(model.DefaultSortingOrder)
builder.WithDirection(requestModifiers.SortDirection)
builder.WithSorting(model.DefaultSortingOrder, requestModifiers.SortDirection)
entries, err := builder.GetEntries()
if err != nil {
@@ -834,6 +839,20 @@ func (h *handler) streamItemContents(w http.ResponseWriter, r *http.Request) {
categories = append(categories, userStarred)
}
entry.Content = proxy.AbsoluteProxyRewriter(h.router, r.Host, entry.Content)
proxyOption := config.Opts.ProxyOption()
for i := range entry.Enclosures {
if proxyOption == "all" || proxyOption != "none" && !urllib.IsHTTPS(entry.Enclosures[i].URL) {
for _, mediaType := range config.Opts.ProxyMediaTypes() {
if strings.HasPrefix(entry.Enclosures[i].MimeType, mediaType+"/") {
entry.Enclosures[i].URL = proxy.AbsoluteProxifyURL(h.router, r.Host, entry.Enclosures[i].URL)
break
}
}
}
}
contentItems[i] = contentItem{
ID: fmt.Sprintf(EntryIDLong, entry.ID),
Title: entry.Title,
@@ -1120,9 +1139,17 @@ func (h *handler) handleReadingListStream(w http.ResponseWriter, r *http.Request
logger.Info("[GoogleReader][ReadingListStreamIDs][ClientIP=%s] xt filter type: %#v", clientIP, s)
}
}
builder.WithoutStatus(model.EntryStatusRemoved)
builder.WithLimit(rm.Count)
builder.WithOrder(model.DefaultSortingOrder)
builder.WithDirection(rm.SortDirection)
builder.WithOffset(rm.Offset)
builder.WithSorting(model.DefaultSortingOrder, rm.SortDirection)
if rm.StartTime > 0 {
builder.AfterDate(time.Unix(rm.StartTime, 0))
}
if rm.StopTime > 0 {
builder.BeforeDate(time.Unix(rm.StopTime, 0))
}
rawEntryIDs, err := builder.GetEntryIDs()
if err != nil {
logger.Error("[GoogleReader][/stream/items/ids#reading-list] [ClientIP=%s] %v", clientIP, err)
@@ -1134,17 +1161,37 @@ func (h *handler) handleReadingListStream(w http.ResponseWriter, r *http.Request
formattedID := strconv.FormatInt(entryID, 10)
itemRefs = append(itemRefs, itemRef{ID: formattedID})
}
json.OK(w, r, streamIDResponse{itemRefs})
totalEntries, err := builder.CountEntries()
if err != nil {
logger.Error("[GoogleReader][/stream/items/ids#reading-list] [ClientIP=%s] %v", clientIP, err)
json.ServerError(w, r, err)
return
}
continuation := 0
if len(itemRefs)+rm.Offset < totalEntries {
continuation = len(itemRefs) + rm.Offset
}
json.OK(w, r, streamIDResponse{itemRefs, continuation})
}
func (h *handler) handleStarredStream(w http.ResponseWriter, r *http.Request, rm RequestModifiers) {
clientIP := request.ClientIP(r)
builder := h.store.NewEntryQueryBuilder(rm.UserID)
builder.WithoutStatus(model.EntryStatusRemoved)
builder.WithStarred(true)
builder.WithLimit(rm.Count)
builder.WithOrder(model.DefaultSortingOrder)
builder.WithDirection(rm.SortDirection)
builder.WithOffset(rm.Offset)
builder.WithSorting(model.DefaultSortingOrder, rm.SortDirection)
if rm.StartTime > 0 {
builder.AfterDate(time.Unix(rm.StartTime, 0))
}
if rm.StopTime > 0 {
builder.BeforeDate(time.Unix(rm.StopTime, 0))
}
rawEntryIDs, err := builder.GetEntryIDs()
if err != nil {
logger.Error("[GoogleReader][/stream/items/ids#starred] [ClientIP=%s] %v", clientIP, err)
@@ -1156,16 +1203,30 @@ func (h *handler) handleStarredStream(w http.ResponseWriter, r *http.Request, rm
formattedID := strconv.FormatInt(entryID, 10)
itemRefs = append(itemRefs, itemRef{ID: formattedID})
}
json.OK(w, r, streamIDResponse{itemRefs})
totalEntries, err := builder.CountEntries()
if err != nil {
logger.Error("[GoogleReader][/stream/items/ids#starred] [ClientIP=%s] %v", clientIP, err)
json.ServerError(w, r, err)
return
}
continuation := 0
if len(itemRefs)+rm.Offset < totalEntries {
continuation = len(itemRefs) + rm.Offset
}
json.OK(w, r, streamIDResponse{itemRefs, continuation})
}
func (h *handler) handleReadStream(w http.ResponseWriter, r *http.Request, rm RequestModifiers) {
clientIP := request.ClientIP(r)
builder := h.store.NewEntryQueryBuilder(rm.UserID)
builder.WithoutStatus(model.EntryStatusRemoved)
builder.WithStatus(model.EntryStatusRead)
builder.WithOrder(model.DefaultSortingOrder)
builder.WithDirection(rm.SortDirection)
builder.WithLimit(rm.Count)
builder.WithOffset(rm.Offset)
builder.WithSorting(model.DefaultSortingOrder, rm.SortDirection)
if rm.StartTime > 0 {
builder.AfterDate(time.Unix(rm.StartTime, 0))
}
@@ -1184,7 +1245,19 @@ func (h *handler) handleReadStream(w http.ResponseWriter, r *http.Request, rm Re
formattedID := strconv.FormatInt(entryID, 10)
itemRefs = append(itemRefs, itemRef{ID: formattedID})
}
json.OK(w, r, streamIDResponse{itemRefs})
totalEntries, err := builder.CountEntries()
if err != nil {
logger.Error("[GoogleReader][/stream/items/ids#read] [ClientIP=%s] %v", clientIP, err)
json.ServerError(w, r, err)
return
}
continuation := 0
if len(itemRefs)+rm.Offset < totalEntries {
continuation = len(itemRefs) + rm.Offset
}
json.OK(w, r, streamIDResponse{itemRefs, continuation})
}
func (h *handler) handleFeedStream(w http.ResponseWriter, r *http.Request, rm RequestModifiers) {
@@ -1197,10 +1270,11 @@ func (h *handler) handleFeedStream(w http.ResponseWriter, r *http.Request, rm Re
}
builder := h.store.NewEntryQueryBuilder(rm.UserID)
builder.WithoutStatus(model.EntryStatusRemoved)
builder.WithFeedID(feedID)
builder.WithLimit(rm.Count)
builder.WithOrder(model.DefaultSortingOrder)
builder.WithDirection(rm.SortDirection)
builder.WithOffset(rm.Offset)
builder.WithSorting(model.DefaultSortingOrder, rm.SortDirection)
if rm.StartTime > 0 {
builder.AfterDate(time.Unix(rm.StartTime, 0))
}
@@ -1210,7 +1284,7 @@ func (h *handler) handleFeedStream(w http.ResponseWriter, r *http.Request, rm Re
rawEntryIDs, err := builder.GetEntryIDs()
if err != nil {
logger.Error("[GoogleReader][/stream/items/ids#starred] [ClientIP=%s] %v", clientIP, err)
logger.Error("[GoogleReader][/stream/items/ids#feed] [ClientIP=%s] %v", clientIP, err)
json.ServerError(w, r, err)
return
}
@@ -1219,5 +1293,17 @@ func (h *handler) handleFeedStream(w http.ResponseWriter, r *http.Request, rm Re
formattedID := strconv.FormatInt(entryID, 10)
itemRefs = append(itemRefs, itemRef{ID: formattedID})
}
json.OK(w, r, streamIDResponse{itemRefs})
totalEntries, err := builder.CountEntries()
if err != nil {
logger.Error("[GoogleReader][/stream/items/ids#feed] [ClientIP=%s] %v", clientIP, err)
json.ServerError(w, r, err)
return
}
continuation := 0
if len(itemRefs)+rm.Offset < totalEntries {
continuation = len(itemRefs) + rm.Offset
}
json.OK(w, r, streamIDResponse{itemRefs, continuation})
}
@@ -1,8 +1,7 @@
// Copyright 2022 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package googlereader // import "miniflux.app/googlereader"
package googlereader // import "miniflux.app/v2/internal/googlereader"
import (
"context"
@@ -12,12 +11,12 @@ import (
"net/http"
"strings"
"miniflux.app/http/request"
"miniflux.app/http/response"
"miniflux.app/http/response/json"
"miniflux.app/logger"
"miniflux.app/model"
"miniflux.app/storage"
"miniflux.app/v2/internal/http/request"
"miniflux.app/v2/internal/http/response"
"miniflux.app/v2/internal/http/response/json"
"miniflux.app/v2/internal/logger"
"miniflux.app/v2/internal/model"
"miniflux.app/v2/internal/storage"
)
type middleware struct {
@@ -1,15 +1,14 @@
// Copyright 2022 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package googlereader // import "miniflux.app/googlereader"
package googlereader // import "miniflux.app/v2/internal/googlereader"
import (
"fmt"
"net/http"
"miniflux.app/http/response"
"miniflux.app/logger"
"miniflux.app/v2/internal/http/response"
"miniflux.app/v2/internal/logger"
)
type login struct {
@@ -61,7 +60,8 @@ type itemRef struct {
}
type streamIDResponse struct {
ItemRefs []itemRef `json:"itemRefs"`
ItemRefs []itemRef `json:"itemRefs"`
Continuation int `json:"continuation,omitempty,string"`
}
type tagsResponse struct {
@@ -1,8 +1,7 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package client // import "miniflux.app/http/client"
package client // import "miniflux.app/v2/internal/http/client"
import (
"bytes"
@@ -17,10 +16,10 @@ import (
"strings"
"time"
"miniflux.app/config"
"miniflux.app/errors"
"miniflux.app/logger"
"miniflux.app/timer"
"miniflux.app/v2/internal/config"
"miniflux.app/v2/internal/errors"
"miniflux.app/v2/internal/logger"
"miniflux.app/v2/internal/timer"
)
const (
@@ -29,10 +28,9 @@ const (
)
var (
errInvalidCertificate = "Invalid SSL certificate (original error: %q)"
errTemporaryNetworkOperation = "This website is temporarily unreachable (original error: %q)"
errPermanentNetworkOperation = "This website is permanently unreachable (original error: %q)"
errRequestTimeout = "Website unreachable, the request timed out after %d seconds"
errInvalidCertificate = "Invalid SSL certificate (original error: %q)"
errNetworkOperation = "This website is unreachable (original error: %q)"
errRequestTimeout = "Website unreachable, the request timed out after %d seconds"
)
// Client builds and executes HTTP requests.
@@ -46,9 +44,9 @@ type Client struct {
requestPassword string
requestUserAgent string
requestCookie string
useProxy bool
doNotFollowRedirects bool
customHeaders map[string]string
useProxy bool
doNotFollowRedirects bool
ClientTimeout int
ClientMaxBodySize int64
@@ -113,6 +111,12 @@ func (c *Client) WithAuthorization(authorization string) *Client {
return c
}
// WithCustomHeaders defines custom HTTP headers.
func (c *Client) WithCustomHeaders(customHeaders map[string]string) *Client {
c.customHeaders = customHeaders
return c
}
// WithCacheHeaders defines caching headers.
func (c *Client) WithCacheHeaders(etagHeader, lastModifiedHeader string) *Client {
c.requestEtagHeader = etagHeader
@@ -185,6 +189,22 @@ func (c *Client) PostJSON(data interface{}) (*Response, error) {
return c.executeRequest(request)
}
// PatchJSON performs a Patch HTTP request with a JSON payload.
func (c *Client) PatchJSON(data interface{}) (*Response, error) {
b, err := json.Marshal(data)
if err != nil {
return nil, err
}
request, err := c.buildRequest(http.MethodPatch, bytes.NewReader(b))
if err != nil {
return nil, err
}
request.Header.Add("Content-Type", "application/json")
return c.executeRequest(request)
}
func (c *Client) executeRequest(request *http.Request) (*Response, error) {
defer timer.ExecutionTime(time.Now(), fmt.Sprintf("[HttpClient] inputURL=%s", c.inputURL))
@@ -205,17 +225,11 @@ func (c *Client) executeRequest(request *http.Request) (*Response, error) {
case x509.CertificateInvalidError, x509.HostnameError:
err = errors.NewLocalizedError(errInvalidCertificate, uerr.Err)
case *net.OpError:
if uerr.Err.(*net.OpError).Temporary() {
err = errors.NewLocalizedError(errTemporaryNetworkOperation, uerr.Err)
} else {
err = errors.NewLocalizedError(errPermanentNetworkOperation, uerr.Err)
}
err = errors.NewLocalizedError(errNetworkOperation, uerr.Err)
case net.Error:
nerr := uerr.Err.(net.Error)
if nerr.Timeout() {
err = errors.NewLocalizedError(errRequestTimeout, c.ClientTimeout)
} else if nerr.Temporary() {
err = errors.NewLocalizedError(errTemporaryNetworkOperation, nerr)
}
}
}
@@ -345,6 +359,10 @@ func (c *Client) buildHeaders() http.Header {
headers.Add("Cookie", c.requestCookie)
}
for key, value := range c.customHeaders {
headers.Add(key, value)
}
headers.Add("Connection", "close")
return headers
}
@@ -1,15 +1,32 @@
// Copyright 2020 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package client // import "miniflux.app/http/client"
package client // import "miniflux.app/v2/internal/http/client"
import (
"fmt"
"net/http/httptest"
"os"
"testing"
"github.com/mccutchen/go-httpbin/v2/httpbin"
)
var srv *httptest.Server
func TestMain(m *testing.M) {
srv = httptest.NewServer(httpbin.New())
exitCode := m.Run()
srv.Close()
os.Exit(exitCode)
}
func MakeClient(path string) *Client {
return New(fmt.Sprintf("%s%s", srv.URL, path))
}
func TestClientWithDelay(t *testing.T) {
clt := New("http://httpbin.org/delay/5")
clt := MakeClient("/delay/5")
clt.ClientTimeout = 1
_, err := clt.Get()
if err == nil {
@@ -18,7 +35,7 @@ func TestClientWithDelay(t *testing.T) {
}
func TestClientWithError(t *testing.T) {
clt := New("http://httpbin.org/status/502")
clt := MakeClient("/status/502")
clt.ClientTimeout = 5
response, err := clt.Get()
if err != nil {
@@ -35,7 +52,7 @@ func TestClientWithError(t *testing.T) {
}
func TestClientWithResponseTooLarge(t *testing.T) {
clt := New("http://httpbin.org/bytes/100")
clt := MakeClient("/bytes/100")
clt.ClientMaxBodySize = 10
_, err := clt.Get()
if err == nil {
@@ -44,7 +61,7 @@ func TestClientWithResponseTooLarge(t *testing.T) {
}
func TestClientWithBasicAuth(t *testing.T) {
clt := New("http://httpbin.org/basic-auth/testuser/testpassword")
clt := MakeClient("/basic-auth/testuser/testpassword")
clt.WithCredentials("testuser", "testpassword")
_, err := clt.Get()
if err != nil {

Some files were not shown because too many files have changed in this diff Show More