mirror of
https://github.com/miniflux/v2.git
synced 2025-08-01 17:38:37 +00:00
Merge branch 'main' into sitemap
This commit is contained in:
commit
689132b78c
12 changed files with 256 additions and 184 deletions
8
.github/workflows/codeql-analysis.yml
vendored
8
.github/workflows/codeql-analysis.yml
vendored
|
@ -5,9 +5,17 @@ permissions: read-all
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ main ]
|
branches: [ main ]
|
||||||
|
paths:
|
||||||
|
- '**.js'
|
||||||
|
- '**.go'
|
||||||
|
- '!**_test.go'
|
||||||
pull_request:
|
pull_request:
|
||||||
# The branches below must be a subset of the branches above
|
# The branches below must be a subset of the branches above
|
||||||
branches: [ main ]
|
branches: [ main ]
|
||||||
|
paths:
|
||||||
|
- '**.js'
|
||||||
|
- '**.go'
|
||||||
|
- '!**_test.go'
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '45 22 * * 3'
|
- cron: '45 22 * * 3'
|
||||||
|
|
||||||
|
|
8
.github/workflows/debian_packages.yml
vendored
8
.github/workflows/debian_packages.yml
vendored
|
@ -5,11 +5,11 @@ on:
|
||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- '[0-9]+.[0-9]+.[0-9]+'
|
- '[0-9]+.[0-9]+.[0-9]+'
|
||||||
pull_request:
|
schedule:
|
||||||
branches: [ main ]
|
- cron: '0 0 * * 1,4' # Runs at 00:00 UTC on Monday and Thursday
|
||||||
jobs:
|
jobs:
|
||||||
test-packages:
|
test-packages:
|
||||||
if: github.event.pull_request
|
if: github.event_name == 'schedule'
|
||||||
name: Test Packages
|
name: Test Packages
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
@ -30,7 +30,7 @@ jobs:
|
||||||
- name: List generated files
|
- name: List generated files
|
||||||
run: ls -l *.deb
|
run: ls -l *.deb
|
||||||
build-packages-manually:
|
build-packages-manually:
|
||||||
if: github.event_name != 'pull_request' && github.event_name != 'push'
|
if: github.event_name == 'workflow_dispatch'
|
||||||
name: Build Packages Manually
|
name: Build Packages Manually
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
|
2
.github/workflows/docker.yml
vendored
2
.github/workflows/docker.yml
vendored
|
@ -7,6 +7,8 @@ on:
|
||||||
- '[0-9]+.[0-9]+.[0-9]+'
|
- '[0-9]+.[0-9]+.[0-9]+'
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ main ]
|
branches: [ main ]
|
||||||
|
paths:
|
||||||
|
- 'packaging/docker/**'
|
||||||
jobs:
|
jobs:
|
||||||
docker-images:
|
docker-images:
|
||||||
name: Docker Images
|
name: Docker Images
|
||||||
|
|
8
.github/workflows/rpm_packages.yml
vendored
8
.github/workflows/rpm_packages.yml
vendored
|
@ -5,11 +5,11 @@ on:
|
||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- '[0-9]+.[0-9]+.[0-9]+'
|
- '[0-9]+.[0-9]+.[0-9]+'
|
||||||
pull_request:
|
schedule:
|
||||||
branches: [ main ]
|
- cron: '0 0 * * 1,4' # Runs at 00:00 UTC on Monday and Thursday
|
||||||
jobs:
|
jobs:
|
||||||
test-package:
|
test-package:
|
||||||
if: github.event.pull_request
|
if: github.event_name == 'schedule'
|
||||||
name: Test Packages
|
name: Test Packages
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
@ -21,7 +21,7 @@ jobs:
|
||||||
- name: List generated files
|
- name: List generated files
|
||||||
run: ls -l *.rpm
|
run: ls -l *.rpm
|
||||||
build-package-manually:
|
build-package-manually:
|
||||||
if: github.event_name != 'pull_request' && github.event_name != 'push'
|
if: github.event_name == 'workflow_dispatch'
|
||||||
name: Build Packages Manually
|
name: Build Packages Manually
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -4,7 +4,6 @@ module miniflux.app/v2
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/PuerkitoBio/goquery v1.10.0
|
github.com/PuerkitoBio/goquery v1.10.0
|
||||||
github.com/abadojack/whatlanggo v1.0.1
|
|
||||||
github.com/andybalholm/brotli v1.1.1
|
github.com/andybalholm/brotli v1.1.1
|
||||||
github.com/coreos/go-oidc/v3 v3.11.0
|
github.com/coreos/go-oidc/v3 v3.11.0
|
||||||
github.com/go-webauthn/webauthn v0.11.2
|
github.com/go-webauthn/webauthn v0.11.2
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -1,7 +1,5 @@
|
||||||
github.com/PuerkitoBio/goquery v1.10.0 h1:6fiXdLuUvYs2OJSvNRqlNPoBm6YABE226xrbavY5Wv4=
|
github.com/PuerkitoBio/goquery v1.10.0 h1:6fiXdLuUvYs2OJSvNRqlNPoBm6YABE226xrbavY5Wv4=
|
||||||
github.com/PuerkitoBio/goquery v1.10.0/go.mod h1:TjZZl68Q3eGHNBA8CWaxAN7rOU1EbDz3CWuolcO5Yu4=
|
github.com/PuerkitoBio/goquery v1.10.0/go.mod h1:TjZZl68Q3eGHNBA8CWaxAN7rOU1EbDz3CWuolcO5Yu4=
|
||||||
github.com/abadojack/whatlanggo v1.0.1 h1:19N6YogDnf71CTHm3Mp2qhYfkRdyvbgwWdd2EPxJRG4=
|
|
||||||
github.com/abadojack/whatlanggo v1.0.1/go.mod h1:66WiQbSbJBIlOZMsvbKe5m6pzQovxCH9B/K8tQB2uoc=
|
|
||||||
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
|
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
|
||||||
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
|
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
|
||||||
github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss=
|
github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss=
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
// Postgresql driver import
|
// Postgresql driver import
|
||||||
_ "github.com/lib/pq"
|
pq "github.com/lib/pq"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewConnectionPool configures the database connection pool.
|
// NewConnectionPool configures the database connection pool.
|
||||||
|
@ -32,6 +32,14 @@ func Migrate(db *sql.DB) error {
|
||||||
var currentVersion int
|
var currentVersion int
|
||||||
db.QueryRow(`SELECT version FROM schema_version`).Scan(¤tVersion)
|
db.QueryRow(`SELECT version FROM schema_version`).Scan(¤tVersion)
|
||||||
|
|
||||||
|
driver := ""
|
||||||
|
switch db.Driver().(type) {
|
||||||
|
case *pq.Driver:
|
||||||
|
driver = "postgresql"
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("the driver %s isn't supported", db.Driver()))
|
||||||
|
}
|
||||||
|
|
||||||
slog.Info("Running database migrations",
|
slog.Info("Running database migrations",
|
||||||
slog.Int("current_version", currentVersion),
|
slog.Int("current_version", currentVersion),
|
||||||
slog.Int("latest_version", schemaVersion),
|
slog.Int("latest_version", schemaVersion),
|
||||||
|
@ -45,7 +53,7 @@ func Migrate(db *sql.DB) error {
|
||||||
return fmt.Errorf("[Migration v%d] %v", newVersion, err)
|
return fmt.Errorf("[Migration v%d] %v", newVersion, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := migrations[version](tx); err != nil {
|
if err := migrations[version](tx, driver); err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return fmt.Errorf("[Migration v%d] %v", newVersion, err)
|
return fmt.Errorf("[Migration v%d] %v", newVersion, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,8 @@ import (
|
||||||
var schemaVersion = len(migrations)
|
var schemaVersion = len(migrations)
|
||||||
|
|
||||||
// Order is important. Add new migrations at the end of the list.
|
// Order is important. Add new migrations at the end of the list.
|
||||||
var migrations = []func(tx *sql.Tx) error{
|
var migrations = []func(tx *sql.Tx, driver string) error{
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
CREATE TABLE schema_version (
|
CREATE TABLE schema_version (
|
||||||
version text not null
|
version text not null
|
||||||
|
@ -120,16 +120,19 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, driver string) (err error) {
|
||||||
sql := `
|
if driver == "postgresql" {
|
||||||
|
sql := `
|
||||||
CREATE EXTENSION IF NOT EXISTS hstore;
|
CREATE EXTENSION IF NOT EXISTS hstore;
|
||||||
ALTER TABLE users ADD COLUMN extra hstore;
|
ALTER TABLE users ADD COLUMN extra hstore;
|
||||||
CREATE INDEX users_extra_idx ON users using gin(extra);
|
CREATE INDEX users_extra_idx ON users using gin(extra);
|
||||||
`
|
`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
CREATE TABLE tokens (
|
CREATE TABLE tokens (
|
||||||
id text not null,
|
id text not null,
|
||||||
|
@ -141,7 +144,7 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
CREATE TYPE entry_sorting_direction AS enum('asc', 'desc');
|
CREATE TYPE entry_sorting_direction AS enum('asc', 'desc');
|
||||||
ALTER TABLE users ADD COLUMN entry_direction entry_sorting_direction default 'asc';
|
ALTER TABLE users ADD COLUMN entry_direction entry_sorting_direction default 'asc';
|
||||||
|
@ -149,7 +152,7 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
CREATE TABLE integrations (
|
CREATE TABLE integrations (
|
||||||
user_id int not null,
|
user_id int not null,
|
||||||
|
@ -170,27 +173,27 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `ALTER TABLE feeds ADD COLUMN scraper_rules text default ''`
|
sql := `ALTER TABLE feeds ADD COLUMN scraper_rules text default ''`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `ALTER TABLE feeds ADD COLUMN rewrite_rules text default ''`
|
sql := `ALTER TABLE feeds ADD COLUMN rewrite_rules text default ''`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `ALTER TABLE feeds ADD COLUMN crawler boolean default 'f'`
|
sql := `ALTER TABLE feeds ADD COLUMN crawler boolean default 'f'`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `ALTER TABLE sessions rename to user_sessions`
|
sql := `ALTER TABLE sessions rename to user_sessions`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
DROP TABLE tokens;
|
DROP TABLE tokens;
|
||||||
|
|
||||||
|
@ -204,7 +207,7 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE integrations ADD COLUMN wallabag_enabled bool default 'f';
|
ALTER TABLE integrations ADD COLUMN wallabag_enabled bool default 'f';
|
||||||
ALTER TABLE integrations ADD COLUMN wallabag_url text default '';
|
ALTER TABLE integrations ADD COLUMN wallabag_url text default '';
|
||||||
|
@ -216,12 +219,12 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `ALTER TABLE entries ADD COLUMN starred bool default 'f'`
|
sql := `ALTER TABLE entries ADD COLUMN starred bool default 'f'`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
CREATE INDEX entries_user_status_idx ON entries(user_id, status);
|
CREATE INDEX entries_user_status_idx ON entries(user_id, status);
|
||||||
CREATE INDEX feeds_user_category_idx ON feeds(user_id, category_id);
|
CREATE INDEX feeds_user_category_idx ON feeds(user_id, category_id);
|
||||||
|
@ -229,7 +232,7 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE integrations ADD COLUMN nunux_keeper_enabled bool default 'f';
|
ALTER TABLE integrations ADD COLUMN nunux_keeper_enabled bool default 'f';
|
||||||
ALTER TABLE integrations ADD COLUMN nunux_keeper_url text default '';
|
ALTER TABLE integrations ADD COLUMN nunux_keeper_url text default '';
|
||||||
|
@ -238,17 +241,17 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `ALTER TABLE enclosures ALTER COLUMN size SET DATA TYPE bigint`
|
sql := `ALTER TABLE enclosures ALTER COLUMN size SET DATA TYPE bigint`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `ALTER TABLE entries ADD COLUMN comments_url text default ''`
|
sql := `ALTER TABLE entries ADD COLUMN comments_url text default ''`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE integrations ADD COLUMN pocket_enabled bool default 'f';
|
ALTER TABLE integrations ADD COLUMN pocket_enabled bool default 'f';
|
||||||
ALTER TABLE integrations ADD COLUMN pocket_access_token text default '';
|
ALTER TABLE integrations ADD COLUMN pocket_access_token text default '';
|
||||||
|
@ -257,14 +260,14 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE user_sessions ALTER COLUMN ip SET DATA TYPE inet using ip::inet;
|
ALTER TABLE user_sessions ALTER COLUMN ip SET DATA TYPE inet using ip::inet;
|
||||||
`
|
`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE feeds ADD COLUMN username text default '';
|
ALTER TABLE feeds ADD COLUMN username text default '';
|
||||||
ALTER TABLE feeds ADD COLUMN password text default '';
|
ALTER TABLE feeds ADD COLUMN password text default '';
|
||||||
|
@ -272,7 +275,7 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE entries ADD COLUMN document_vectors tsvector;
|
ALTER TABLE entries ADD COLUMN document_vectors tsvector;
|
||||||
UPDATE entries SET document_vectors = to_tsvector(substring(title || ' ' || coalesce(content, '') for 1000000));
|
UPDATE entries SET document_vectors = to_tsvector(substring(title || ' ' || coalesce(content, '') for 1000000));
|
||||||
|
@ -281,12 +284,12 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `ALTER TABLE feeds ADD COLUMN user_agent text default ''`
|
sql := `ALTER TABLE feeds ADD COLUMN user_agent text default ''`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
UPDATE
|
UPDATE
|
||||||
entries
|
entries
|
||||||
|
@ -296,17 +299,17 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `ALTER TABLE users ADD COLUMN keyboard_shortcuts boolean default 't'`
|
sql := `ALTER TABLE users ADD COLUMN keyboard_shortcuts boolean default 't'`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `ALTER TABLE feeds ADD COLUMN disabled boolean default 'f';`
|
sql := `ALTER TABLE feeds ADD COLUMN disabled boolean default 'f';`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE users ALTER COLUMN theme SET DEFAULT 'light_serif';
|
ALTER TABLE users ALTER COLUMN theme SET DEFAULT 'light_serif';
|
||||||
UPDATE users SET theme='light_serif' WHERE theme='default';
|
UPDATE users SET theme='light_serif' WHERE theme='default';
|
||||||
|
@ -316,7 +319,7 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE entries ADD COLUMN changed_at timestamp with time zone;
|
ALTER TABLE entries ADD COLUMN changed_at timestamp with time zone;
|
||||||
UPDATE entries SET changed_at = published_at;
|
UPDATE entries SET changed_at = published_at;
|
||||||
|
@ -325,7 +328,7 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
CREATE TABLE api_keys (
|
CREATE TABLE api_keys (
|
||||||
id serial not null,
|
id serial not null,
|
||||||
|
@ -341,7 +344,7 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE entries ADD COLUMN share_code text not null default '';
|
ALTER TABLE entries ADD COLUMN share_code text not null default '';
|
||||||
CREATE UNIQUE INDEX entries_share_code_idx ON entries USING btree(share_code) WHERE share_code <> '';
|
CREATE UNIQUE INDEX entries_share_code_idx ON entries USING btree(share_code) WHERE share_code <> '';
|
||||||
|
@ -349,12 +352,12 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `CREATE INDEX enclosures_user_entry_url_idx ON enclosures(user_id, entry_id, md5(url))`
|
sql := `CREATE INDEX enclosures_user_entry_url_idx ON enclosures(user_id, entry_id, md5(url))`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE feeds ADD COLUMN next_check_at timestamp with time zone default now();
|
ALTER TABLE feeds ADD COLUMN next_check_at timestamp with time zone default now();
|
||||||
CREATE INDEX entries_user_feed_idx ON entries (user_id, feed_id);
|
CREATE INDEX entries_user_feed_idx ON entries (user_id, feed_id);
|
||||||
|
@ -362,52 +365,52 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `ALTER TABLE feeds ADD COLUMN ignore_http_cache bool default false`
|
sql := `ALTER TABLE feeds ADD COLUMN ignore_http_cache bool default false`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `ALTER TABLE users ADD COLUMN entries_per_page int default 100`
|
sql := `ALTER TABLE users ADD COLUMN entries_per_page int default 100`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `ALTER TABLE users ADD COLUMN show_reading_time boolean default 't'`
|
sql := `ALTER TABLE users ADD COLUMN show_reading_time boolean default 't'`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `CREATE INDEX entries_id_user_status_idx ON entries USING btree (id, user_id, status)`
|
sql := `CREATE INDEX entries_id_user_status_idx ON entries USING btree (id, user_id, status)`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `ALTER TABLE feeds ADD COLUMN fetch_via_proxy bool default false`
|
sql := `ALTER TABLE feeds ADD COLUMN fetch_via_proxy bool default false`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `CREATE INDEX entries_feed_id_status_hash_idx ON entries USING btree (feed_id, status, hash)`
|
sql := `CREATE INDEX entries_feed_id_status_hash_idx ON entries USING btree (feed_id, status, hash)`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `CREATE INDEX entries_user_id_status_starred_idx ON entries (user_id, status, starred)`
|
sql := `CREATE INDEX entries_user_id_status_starred_idx ON entries (user_id, status, starred)`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `ALTER TABLE users ADD COLUMN entry_swipe boolean default 't'`
|
sql := `ALTER TABLE users ADD COLUMN entry_swipe boolean default 't'`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `ALTER TABLE integrations DROP COLUMN fever_password`
|
sql := `ALTER TABLE integrations DROP COLUMN fever_password`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE feeds
|
ALTER TABLE feeds
|
||||||
ADD COLUMN blocklist_rules text not null default '',
|
ADD COLUMN blocklist_rules text not null default '',
|
||||||
|
@ -416,12 +419,12 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `ALTER TABLE entries ADD COLUMN reading_time int not null default 0`
|
sql := `ALTER TABLE entries ADD COLUMN reading_time int not null default 0`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE entries ADD COLUMN created_at timestamp with time zone not null default now();
|
ALTER TABLE entries ADD COLUMN created_at timestamp with time zone not null default now();
|
||||||
UPDATE entries SET created_at = published_at;
|
UPDATE entries SET created_at = published_at;
|
||||||
|
@ -429,7 +432,7 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, driver string) (err error) {
|
||||||
_, err = tx.Exec(`
|
_, err = tx.Exec(`
|
||||||
ALTER TABLE users
|
ALTER TABLE users
|
||||||
ADD column stylesheet text not null default '',
|
ADD column stylesheet text not null default '',
|
||||||
|
@ -440,63 +443,69 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = tx.Exec(`
|
if driver == "postgresql" {
|
||||||
DECLARE my_cursor CURSOR FOR
|
_, err = tx.Exec(`
|
||||||
SELECT
|
DECLARE my_cursor CURSOR FOR
|
||||||
id,
|
SELECT
|
||||||
COALESCE(extra->'custom_css', '') as custom_css,
|
id,
|
||||||
COALESCE(extra->'google_id', '') as google_id,
|
COALESCE(extra->'custom_css', '') as custom_css,
|
||||||
COALESCE(extra->'oidc_id', '') as oidc_id
|
COALESCE(extra->'google_id', '') as google_id,
|
||||||
FROM users
|
COALESCE(extra->'oidc_id', '') as oidc_id
|
||||||
FOR UPDATE
|
FROM users
|
||||||
`)
|
FOR UPDATE
|
||||||
if err != nil {
|
`)
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer tx.Exec("CLOSE my_cursor")
|
|
||||||
|
|
||||||
for {
|
|
||||||
var (
|
|
||||||
userID int64
|
|
||||||
customStylesheet string
|
|
||||||
googleID string
|
|
||||||
oidcID string
|
|
||||||
)
|
|
||||||
|
|
||||||
if err := tx.QueryRow(`FETCH NEXT FROM my_cursor`).Scan(&userID, &customStylesheet, &googleID, &oidcID); err != nil {
|
|
||||||
if err == sql.ErrNoRows {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := tx.Exec(
|
|
||||||
`UPDATE
|
|
||||||
users
|
|
||||||
SET
|
|
||||||
stylesheet=$2,
|
|
||||||
google_id=$3,
|
|
||||||
openid_connect_id=$4
|
|
||||||
WHERE
|
|
||||||
id=$1
|
|
||||||
`,
|
|
||||||
userID, customStylesheet, googleID, oidcID)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
defer tx.Exec("CLOSE my_cursor")
|
||||||
|
|
||||||
|
for {
|
||||||
|
var (
|
||||||
|
userID int64
|
||||||
|
customStylesheet string
|
||||||
|
googleID string
|
||||||
|
oidcID string
|
||||||
|
)
|
||||||
|
|
||||||
|
if err := tx.QueryRow(`FETCH NEXT FROM my_cursor`).Scan(&userID, &customStylesheet, &googleID, &oidcID); err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := tx.Exec(
|
||||||
|
`UPDATE
|
||||||
|
users
|
||||||
|
SET
|
||||||
|
stylesheet=$2,
|
||||||
|
google_id=$3,
|
||||||
|
openid_connect_id=$4
|
||||||
|
WHERE
|
||||||
|
id=$1
|
||||||
|
`,
|
||||||
|
userID, customStylesheet, googleID, oidcID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, driver string) (err error) {
|
||||||
|
if driver == "postgresql" {
|
||||||
|
if _, err = tx.Exec(`ALTER TABLE users DROP COLUMN extra;`); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
_, err = tx.Exec(`
|
_, err = tx.Exec(`
|
||||||
ALTER TABLE users DROP COLUMN extra;
|
|
||||||
CREATE UNIQUE INDEX users_google_id_idx ON users(google_id) WHERE google_id <> '';
|
CREATE UNIQUE INDEX users_google_id_idx ON users(google_id) WHERE google_id <> '';
|
||||||
CREATE UNIQUE INDEX users_openid_connect_id_idx ON users(openid_connect_id) WHERE openid_connect_id <> '';
|
CREATE UNIQUE INDEX users_openid_connect_id_idx ON users(openid_connect_id) WHERE openid_connect_id <> '';
|
||||||
`)
|
`)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
_, err = tx.Exec(`
|
_, err = tx.Exec(`
|
||||||
CREATE INDEX entries_feed_url_idx ON entries(feed_id, url);
|
CREATE INDEX entries_feed_url_idx ON entries(feed_id, url);
|
||||||
CREATE INDEX entries_user_status_feed_idx ON entries(user_id, status, feed_id);
|
CREATE INDEX entries_user_status_feed_idx ON entries(user_id, status, feed_id);
|
||||||
|
@ -504,7 +513,7 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
`)
|
`)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
_, err = tx.Exec(`
|
_, err = tx.Exec(`
|
||||||
CREATE TABLE acme_cache (
|
CREATE TABLE acme_cache (
|
||||||
key varchar(400) not null primary key,
|
key varchar(400) not null primary key,
|
||||||
|
@ -514,13 +523,13 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
`)
|
`)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
_, err = tx.Exec(`
|
_, err = tx.Exec(`
|
||||||
ALTER TABLE feeds ADD COLUMN allow_self_signed_certificates boolean not null default false
|
ALTER TABLE feeds ADD COLUMN allow_self_signed_certificates boolean not null default false
|
||||||
`)
|
`)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
CREATE TYPE webapp_display_mode AS enum('fullscreen', 'standalone', 'minimal-ui', 'browser');
|
CREATE TYPE webapp_display_mode AS enum('fullscreen', 'standalone', 'minimal-ui', 'browser');
|
||||||
ALTER TABLE users ADD COLUMN display_mode webapp_display_mode default 'standalone';
|
ALTER TABLE users ADD COLUMN display_mode webapp_display_mode default 'standalone';
|
||||||
|
@ -528,24 +537,24 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `ALTER TABLE feeds ADD COLUMN cookie text default ''`
|
sql := `ALTER TABLE feeds ADD COLUMN cookie text default ''`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
_, err = tx.Exec(`
|
_, err = tx.Exec(`
|
||||||
ALTER TABLE categories ADD COLUMN hide_globally boolean not null default false
|
ALTER TABLE categories ADD COLUMN hide_globally boolean not null default false
|
||||||
`)
|
`)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
_, err = tx.Exec(`
|
_, err = tx.Exec(`
|
||||||
ALTER TABLE feeds ADD COLUMN hide_globally boolean not null default false
|
ALTER TABLE feeds ADD COLUMN hide_globally boolean not null default false
|
||||||
`)
|
`)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE integrations ADD COLUMN telegram_bot_enabled bool default 'f';
|
ALTER TABLE integrations ADD COLUMN telegram_bot_enabled bool default 'f';
|
||||||
ALTER TABLE integrations ADD COLUMN telegram_bot_token text default '';
|
ALTER TABLE integrations ADD COLUMN telegram_bot_token text default '';
|
||||||
|
@ -554,7 +563,7 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
CREATE TYPE entry_sorting_order AS enum('published_at', 'created_at');
|
CREATE TYPE entry_sorting_order AS enum('published_at', 'created_at');
|
||||||
ALTER TABLE users ADD COLUMN entry_order entry_sorting_order default 'published_at';
|
ALTER TABLE users ADD COLUMN entry_order entry_sorting_order default 'published_at';
|
||||||
|
@ -562,7 +571,7 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE integrations ADD COLUMN googlereader_enabled bool default 'f';
|
ALTER TABLE integrations ADD COLUMN googlereader_enabled bool default 'f';
|
||||||
ALTER TABLE integrations ADD COLUMN googlereader_username text default '';
|
ALTER TABLE integrations ADD COLUMN googlereader_username text default '';
|
||||||
|
@ -571,7 +580,7 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE integrations ADD COLUMN espial_enabled bool default 'f';
|
ALTER TABLE integrations ADD COLUMN espial_enabled bool default 'f';
|
||||||
ALTER TABLE integrations ADD COLUMN espial_url text default '';
|
ALTER TABLE integrations ADD COLUMN espial_url text default '';
|
||||||
|
@ -581,7 +590,7 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE integrations ADD COLUMN linkding_enabled bool default 'f';
|
ALTER TABLE integrations ADD COLUMN linkding_enabled bool default 'f';
|
||||||
ALTER TABLE integrations ADD COLUMN linkding_url text default '';
|
ALTER TABLE integrations ADD COLUMN linkding_url text default '';
|
||||||
|
@ -590,38 +599,38 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
_, err = tx.Exec(`
|
_, err = tx.Exec(`
|
||||||
ALTER TABLE feeds ADD COLUMN url_rewrite_rules text not null default ''
|
ALTER TABLE feeds ADD COLUMN url_rewrite_rules text not null default ''
|
||||||
`)
|
`)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
_, err = tx.Exec(`
|
_, err = tx.Exec(`
|
||||||
ALTER TABLE users ADD COLUMN default_reading_speed int default 265;
|
ALTER TABLE users ADD COLUMN default_reading_speed int default 265;
|
||||||
ALTER TABLE users ADD COLUMN cjk_reading_speed int default 500;
|
ALTER TABLE users ADD COLUMN cjk_reading_speed int default 500;
|
||||||
`)
|
`)
|
||||||
return
|
return
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
_, err = tx.Exec(`
|
_, err = tx.Exec(`
|
||||||
ALTER TABLE users ADD COLUMN default_home_page text default 'unread';
|
ALTER TABLE users ADD COLUMN default_home_page text default 'unread';
|
||||||
`)
|
`)
|
||||||
return
|
return
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
_, err = tx.Exec(`
|
_, err = tx.Exec(`
|
||||||
ALTER TABLE integrations ADD COLUMN wallabag_only_url bool default 'f';
|
ALTER TABLE integrations ADD COLUMN wallabag_only_url bool default 'f';
|
||||||
`)
|
`)
|
||||||
return
|
return
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
_, err = tx.Exec(`
|
_, err = tx.Exec(`
|
||||||
ALTER TABLE users ADD COLUMN categories_sorting_order text not null default 'unread_count';
|
ALTER TABLE users ADD COLUMN categories_sorting_order text not null default 'unread_count';
|
||||||
`)
|
`)
|
||||||
return
|
return
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE integrations ADD COLUMN matrix_bot_enabled bool default 'f';
|
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_user text default '';
|
||||||
|
@ -632,18 +641,18 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return
|
return
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `ALTER TABLE users ADD COLUMN double_tap boolean default 't'`
|
sql := `ALTER TABLE users ADD COLUMN double_tap boolean default 't'`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
_, err = tx.Exec(`
|
_, err = tx.Exec(`
|
||||||
ALTER TABLE entries ADD COLUMN tags text[] default '{}';
|
ALTER TABLE entries ADD COLUMN tags text[] default '{}';
|
||||||
`)
|
`)
|
||||||
return
|
return
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE users RENAME double_tap TO gesture_nav;
|
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 DATA TYPE text using case when gesture_nav = true then 'tap' when gesture_nav = false then 'none' end;
|
||||||
|
@ -652,14 +661,14 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE integrations ADD COLUMN linkding_tags text default '';
|
ALTER TABLE integrations ADD COLUMN linkding_tags text default '';
|
||||||
`
|
`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE feeds ADD COLUMN no_media_player boolean default 'f';
|
ALTER TABLE feeds ADD COLUMN no_media_player boolean default 'f';
|
||||||
ALTER TABLE enclosures ADD COLUMN media_progression int default 0;
|
ALTER TABLE enclosures ADD COLUMN media_progression int default 0;
|
||||||
|
@ -667,14 +676,14 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE integrations ADD COLUMN linkding_mark_as_unread bool default 'f';
|
ALTER TABLE integrations ADD COLUMN linkding_mark_as_unread bool default 'f';
|
||||||
`
|
`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
// Delete duplicated rows
|
// Delete duplicated rows
|
||||||
sql := `
|
sql := `
|
||||||
DELETE FROM enclosures a USING enclosures b
|
DELETE FROM enclosures a USING enclosures b
|
||||||
|
@ -702,12 +711,12 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `ALTER TABLE users ADD COLUMN mark_read_on_view boolean default 't'`
|
sql := `ALTER TABLE users ADD COLUMN mark_read_on_view boolean default 't'`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE integrations ADD COLUMN notion_enabled bool default 'f';
|
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_token text default '';
|
||||||
|
@ -716,7 +725,7 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE integrations ADD COLUMN readwise_enabled bool default 'f';
|
ALTER TABLE integrations ADD COLUMN readwise_enabled bool default 'f';
|
||||||
ALTER TABLE integrations ADD COLUMN readwise_api_key text default '';
|
ALTER TABLE integrations ADD COLUMN readwise_api_key text default '';
|
||||||
|
@ -724,7 +733,7 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE integrations ADD COLUMN apprise_enabled bool default 'f';
|
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_url text default '';
|
||||||
|
@ -733,7 +742,7 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE integrations ADD COLUMN shiori_enabled bool default 'f';
|
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_url text default '';
|
||||||
|
@ -743,7 +752,7 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE integrations ADD COLUMN shaarli_enabled bool default 'f';
|
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_url text default '';
|
||||||
|
@ -752,13 +761,13 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
_, err = tx.Exec(`
|
_, err = tx.Exec(`
|
||||||
ALTER TABLE feeds ADD COLUMN apprise_service_urls text default '';
|
ALTER TABLE feeds ADD COLUMN apprise_service_urls text default '';
|
||||||
`)
|
`)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE integrations ADD COLUMN webhook_enabled bool default 'f';
|
ALTER TABLE integrations ADD COLUMN webhook_enabled bool default 'f';
|
||||||
ALTER TABLE integrations ADD COLUMN webhook_url text default '';
|
ALTER TABLE integrations ADD COLUMN webhook_url text default '';
|
||||||
|
@ -767,7 +776,7 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE integrations ADD COLUMN telegram_bot_topic_id int;
|
ALTER TABLE integrations ADD COLUMN telegram_bot_topic_id int;
|
||||||
ALTER TABLE integrations ADD COLUMN telegram_bot_disable_web_page_preview bool default 'f';
|
ALTER TABLE integrations ADD COLUMN telegram_bot_disable_web_page_preview bool default 'f';
|
||||||
|
@ -776,14 +785,14 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE integrations ADD COLUMN telegram_bot_disable_buttons bool default 'f';
|
ALTER TABLE integrations ADD COLUMN telegram_bot_disable_buttons bool default 'f';
|
||||||
`
|
`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
-- Speed up has_enclosure
|
-- Speed up has_enclosure
|
||||||
CREATE INDEX enclosures_entry_id_idx ON enclosures(entry_id);
|
CREATE INDEX enclosures_entry_id_idx ON enclosures(entry_id);
|
||||||
|
@ -799,7 +808,7 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE integrations ADD COLUMN rssbridge_enabled bool default 'f';
|
ALTER TABLE integrations ADD COLUMN rssbridge_enabled bool default 'f';
|
||||||
ALTER TABLE integrations ADD COLUMN rssbridge_url text default '';
|
ALTER TABLE integrations ADD COLUMN rssbridge_url text default '';
|
||||||
|
@ -807,7 +816,7 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return
|
return
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
_, err = tx.Exec(`
|
_, err = tx.Exec(`
|
||||||
CREATE TABLE webauthn_credentials (
|
CREATE TABLE webauthn_credentials (
|
||||||
handle bytea primary key,
|
handle bytea primary key,
|
||||||
|
@ -825,7 +834,7 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
`)
|
`)
|
||||||
return
|
return
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE integrations ADD COLUMN omnivore_enabled bool default 'f';
|
ALTER TABLE integrations ADD COLUMN omnivore_enabled bool default 'f';
|
||||||
ALTER TABLE integrations ADD COLUMN omnivore_api_key text default '';
|
ALTER TABLE integrations ADD COLUMN omnivore_api_key text default '';
|
||||||
|
@ -834,7 +843,7 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return
|
return
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE integrations ADD COLUMN linkace_enabled bool default 'f';
|
ALTER TABLE integrations ADD COLUMN linkace_enabled bool default 'f';
|
||||||
ALTER TABLE integrations ADD COLUMN linkace_url text default '';
|
ALTER TABLE integrations ADD COLUMN linkace_url text default '';
|
||||||
|
@ -846,7 +855,7 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE integrations ADD COLUMN linkwarden_enabled bool default 'f';
|
ALTER TABLE integrations ADD COLUMN linkwarden_enabled bool default 'f';
|
||||||
ALTER TABLE integrations ADD COLUMN linkwarden_url text default '';
|
ALTER TABLE integrations ADD COLUMN linkwarden_url text default '';
|
||||||
|
@ -855,7 +864,7 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE integrations ADD COLUMN readeck_enabled bool default 'f';
|
ALTER TABLE integrations ADD COLUMN readeck_enabled bool default 'f';
|
||||||
ALTER TABLE integrations ADD COLUMN readeck_only_url bool default 'f';
|
ALTER TABLE integrations ADD COLUMN readeck_only_url bool default 'f';
|
||||||
|
@ -866,29 +875,29 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `ALTER TABLE feeds ADD COLUMN disable_http2 bool default 'f'`
|
sql := `ALTER TABLE feeds ADD COLUMN disable_http2 bool default 'f'`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `ALTER TABLE users ADD COLUMN media_playback_rate numeric default 1;`
|
sql := `ALTER TABLE users ADD COLUMN media_playback_rate numeric default 1;`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
// the WHERE part speed-up the request a lot
|
// the WHERE part speed-up the request a lot
|
||||||
sql := `UPDATE entries SET tags = array_remove(tags, '') WHERE '' = ANY(tags);`
|
sql := `UPDATE entries SET tags = array_remove(tags, '') WHERE '' = ANY(tags);`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
// Entry URLs can exceeds btree maximum size
|
// Entry URLs can exceeds btree maximum size
|
||||||
// Checking entry existence is now using entries_feed_id_status_hash_idx index
|
// Checking entry existence is now using entries_feed_id_status_hash_idx index
|
||||||
_, err = tx.Exec(`DROP INDEX entries_feed_url_idx`)
|
_, err = tx.Exec(`DROP INDEX entries_feed_url_idx`)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE integrations ADD COLUMN raindrop_enabled bool default 'f';
|
ALTER TABLE integrations ADD COLUMN raindrop_enabled bool default 'f';
|
||||||
ALTER TABLE integrations ADD COLUMN raindrop_token text default '';
|
ALTER TABLE integrations ADD COLUMN raindrop_token text default '';
|
||||||
|
@ -898,12 +907,12 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `ALTER TABLE feeds ADD COLUMN description text default ''`
|
sql := `ALTER TABLE feeds ADD COLUMN description text default ''`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE users
|
ALTER TABLE users
|
||||||
ADD COLUMN block_filter_entry_rules text not null default '',
|
ADD COLUMN block_filter_entry_rules text not null default '',
|
||||||
|
@ -912,7 +921,7 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE integrations ADD COLUMN betula_url text default '';
|
ALTER TABLE integrations ADD COLUMN betula_url text default '';
|
||||||
ALTER TABLE integrations ADD COLUMN betula_token text default '';
|
ALTER TABLE integrations ADD COLUMN betula_token text default '';
|
||||||
|
@ -921,7 +930,7 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE integrations ADD COLUMN ntfy_enabled bool default 'f';
|
ALTER TABLE integrations ADD COLUMN ntfy_enabled bool default 'f';
|
||||||
ALTER TABLE integrations ADD COLUMN ntfy_url text default '';
|
ALTER TABLE integrations ADD COLUMN ntfy_url text default '';
|
||||||
|
@ -937,22 +946,22 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `ALTER TABLE users ADD COLUMN mark_read_on_media_player_completion bool default 'f';`
|
sql := `ALTER TABLE users ADD COLUMN mark_read_on_media_player_completion bool default 'f';`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `ALTER TABLE users ADD COLUMN custom_js text not null default '';`
|
sql := `ALTER TABLE users ADD COLUMN custom_js text not null default '';`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `ALTER TABLE users ADD COLUMN external_font_hosts text not null default '';`
|
sql := `ALTER TABLE users ADD COLUMN external_font_hosts text not null default '';`
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
func(tx *sql.Tx) (err error) {
|
func(tx *sql.Tx, _ string) (err error) {
|
||||||
sql := `
|
sql := `
|
||||||
ALTER TABLE integrations ADD COLUMN cubox_enabled bool default 'f';
|
ALTER TABLE integrations ADD COLUMN cubox_enabled bool default 'f';
|
||||||
ALTER TABLE integrations ADD COLUMN cubox_api_link text default '';
|
ALTER TABLE integrations ADD COLUMN cubox_api_link text default '';
|
||||||
|
|
|
@ -6,7 +6,6 @@ package oauth2 // import "miniflux.app/v2/internal/oauth2"
|
||||||
import (
|
import (
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"io"
|
|
||||||
|
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
|
|
||||||
|
@ -33,17 +32,14 @@ func (u *Authorization) CodeVerifier() string {
|
||||||
|
|
||||||
func GenerateAuthorization(config *oauth2.Config) *Authorization {
|
func GenerateAuthorization(config *oauth2.Config) *Authorization {
|
||||||
codeVerifier := crypto.GenerateRandomStringHex(32)
|
codeVerifier := crypto.GenerateRandomStringHex(32)
|
||||||
|
sum := sha256.Sum256([]byte(codeVerifier))
|
||||||
sha2 := sha256.New()
|
|
||||||
io.WriteString(sha2, codeVerifier)
|
|
||||||
codeChallenge := base64.RawURLEncoding.EncodeToString(sha2.Sum(nil))
|
|
||||||
|
|
||||||
state := crypto.GenerateRandomStringHex(24)
|
state := crypto.GenerateRandomStringHex(24)
|
||||||
|
|
||||||
authUrl := config.AuthCodeURL(
|
authUrl := config.AuthCodeURL(
|
||||||
state,
|
state,
|
||||||
oauth2.SetAuthURLParam("code_challenge_method", "S256"),
|
oauth2.SetAuthURLParam("code_challenge_method", "S256"),
|
||||||
oauth2.SetAuthURLParam("code_challenge", codeChallenge),
|
oauth2.SetAuthURLParam("code_challenge", base64.RawURLEncoding.EncodeToString(sum[:])),
|
||||||
)
|
)
|
||||||
|
|
||||||
return &Authorization{
|
return &Authorization{
|
||||||
|
|
|
@ -7,33 +7,37 @@ package readingtime
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
"strings"
|
"strings"
|
||||||
|
"unicode"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
"miniflux.app/v2/internal/reader/sanitizer"
|
"miniflux.app/v2/internal/reader/sanitizer"
|
||||||
|
|
||||||
"github.com/abadojack/whatlanggo"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// EstimateReadingTime returns the estimated reading time of an article in minute.
|
// EstimateReadingTime returns the estimated reading time of an article in minute.
|
||||||
func EstimateReadingTime(content string, defaultReadingSpeed, cjkReadingSpeed int) int {
|
func EstimateReadingTime(content string, defaultReadingSpeed, cjkReadingSpeed int) int {
|
||||||
sanitizedContent := sanitizer.StripTags(content)
|
sanitizedContent := sanitizer.StripTags(content)
|
||||||
|
truncationPoint := min(len(sanitizedContent), 50)
|
||||||
|
|
||||||
// Litterature on language detection says that around 100 signes is enough, we're safe here.
|
if isCJK(sanitizedContent[:truncationPoint]) {
|
||||||
truncationPoint := min(len(sanitizedContent), 250)
|
|
||||||
|
|
||||||
// We're only interested in identifying Japanse/Chinese/Korean
|
|
||||||
options := whatlanggo.Options{
|
|
||||||
Whitelist: map[whatlanggo.Lang]bool{
|
|
||||||
whatlanggo.Jpn: true,
|
|
||||||
whatlanggo.Cmn: true,
|
|
||||||
whatlanggo.Kor: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
langInfo := whatlanggo.DetectWithOptions(sanitizedContent[:truncationPoint], options)
|
|
||||||
|
|
||||||
if langInfo.IsReliable() {
|
|
||||||
return int(math.Ceil(float64(utf8.RuneCountInString(sanitizedContent)) / float64(cjkReadingSpeed)))
|
return int(math.Ceil(float64(utf8.RuneCountInString(sanitizedContent)) / float64(cjkReadingSpeed)))
|
||||||
}
|
}
|
||||||
nbOfWords := len(strings.Fields(sanitizedContent))
|
return int(math.Ceil(float64(len(strings.Fields(sanitizedContent))) / float64(defaultReadingSpeed)))
|
||||||
return int(math.Ceil(float64(nbOfWords) / float64(defaultReadingSpeed)))
|
}
|
||||||
|
|
||||||
|
func isCJK(text string) bool {
|
||||||
|
totalCJK := 0
|
||||||
|
|
||||||
|
for _, r := range text[:min(len(text), 50)] {
|
||||||
|
if unicode.Is(unicode.Han, r) ||
|
||||||
|
unicode.Is(unicode.Hangul, r) ||
|
||||||
|
unicode.Is(unicode.Hiragana, r) ||
|
||||||
|
unicode.Is(unicode.Katakana, r) ||
|
||||||
|
unicode.Is(unicode.Yi, r) ||
|
||||||
|
unicode.Is(unicode.Bopomofo, r) {
|
||||||
|
totalCJK++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if at least 50% of the text is CJK, odds are that the text is in CJK.
|
||||||
|
return totalCJK > len(text)/50
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ package validator // import "miniflux.app/v2/internal/validator"
|
||||||
import (
|
import (
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
|
||||||
"miniflux.app/v2/internal/locale"
|
"miniflux.app/v2/internal/locale"
|
||||||
"miniflux.app/v2/internal/model"
|
"miniflux.app/v2/internal/model"
|
||||||
|
@ -22,6 +23,10 @@ func ValidateUserCreationWithPassword(store *storage.Storage, request *model.Use
|
||||||
return locale.NewLocalizedError("error.user_already_exists")
|
return locale.NewLocalizedError("error.user_already_exists")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := validateUsername(request.Username); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if err := validatePassword(request.Password); err != nil {
|
if err := validatePassword(request.Password); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -146,6 +151,23 @@ func validatePassword(password string) *locale.LocalizedError {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validateUsername return an error if the `username` argument contains
|
||||||
|
// a character that isn't alphanumerical nor `_` and `-`.
|
||||||
|
func validateUsername(username string) *locale.LocalizedError {
|
||||||
|
if strings.ContainsFunc(username, func(r rune) bool {
|
||||||
|
if unicode.IsLetter(r) || unicode.IsNumber(r) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if r == '_' || r == '-' || r == '@' || r == '.' {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}) {
|
||||||
|
return locale.NewLocalizedError("error.invalid_username")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func validateTheme(theme string) *locale.LocalizedError {
|
func validateTheme(theme string) *locale.LocalizedError {
|
||||||
themes := model.Themes()
|
themes := model.Themes()
|
||||||
if _, found := themes[theme]; !found {
|
if _, found := themes[theme]; !found {
|
||||||
|
|
|
@ -3,7 +3,11 @@
|
||||||
|
|
||||||
package validator // import "miniflux.app/v2/internal/validator"
|
package validator // import "miniflux.app/v2/internal/validator"
|
||||||
|
|
||||||
import "testing"
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"miniflux.app/v2/internal/locale"
|
||||||
|
)
|
||||||
|
|
||||||
func TestIsValidURL(t *testing.T) {
|
func TestIsValidURL(t *testing.T) {
|
||||||
scenarios := map[string]bool{
|
scenarios := map[string]bool{
|
||||||
|
@ -77,3 +81,25 @@ func TestIsValidDomain(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestValidateUsername(t *testing.T) {
|
||||||
|
scenarios := map[string]*locale.LocalizedError{
|
||||||
|
"jvoisin": nil,
|
||||||
|
"j.voisin": nil,
|
||||||
|
"j@vois.in": nil,
|
||||||
|
"invalid username": locale.NewLocalizedError("error.invalid_username"),
|
||||||
|
}
|
||||||
|
|
||||||
|
for username, expected := range scenarios {
|
||||||
|
result := validateUsername(username)
|
||||||
|
if expected == nil {
|
||||||
|
if result != nil {
|
||||||
|
t.Errorf(`got an unexpected error for %q instead of nil: %v`, username, result)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if result == nil {
|
||||||
|
t.Errorf(`expected an error, got nil.`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue