aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Frédéric Guillot <fred@miniflux.net>2018-06-19 22:58:29 -0700
committerGravatar Frédéric Guillot <fred@miniflux.net>2018-06-19 22:58:29 -0700
commitbddca15b69692bd055c507f2469e68dca1e56098 (patch)
tree913989e170cc3ac46558c682f8ec10813a0ae3c5
parent261695c14c2d768f392cfb774e7940660edaa3d9 (diff)
Add new fields for feed username/password
-rw-r--r--api/feed.go19
-rw-r--r--api/payload.go45
-rw-r--r--api/subscription.go8
-rw-r--r--http/client/client.go9
-rwxr-xr-xlocale/translations.go9
-rw-r--r--locale/translations/fr_FR.json5
-rw-r--r--model/feed.go10
-rw-r--r--reader/feed/handler.go6
-rw-r--r--reader/subscription/finder.go3
-rw-r--r--sql/schema_version_19.sql2
-rw-r--r--sql/sql.go5
-rw-r--r--storage/feed.go19
-rw-r--r--storage/migration.go2
-rw-r--r--template/common.go2
-rw-r--r--template/html/add_subscription.html12
-rw-r--r--template/html/choose_subscription.html10
-rw-r--r--template/html/edit_feed.html6
-rw-r--r--template/views.go36
-rw-r--r--ui/feed_edit.go2
-rw-r--r--ui/form/feed.go6
-rw-r--r--ui/form/subscription.go4
-rw-r--r--ui/static/bin.go2
-rw-r--r--ui/static/css.go6
-rw-r--r--ui/static/css/common.css11
-rw-r--r--ui/static/js.go2
-rw-r--r--ui/subscription_choose.go9
-rw-r--r--ui/subscription_submit.go17
27 files changed, 201 insertions, 66 deletions
diff --git a/api/feed.go b/api/feed.go
index f6e3c16..351457f 100644
--- a/api/feed.go
+++ b/api/feed.go
@@ -15,18 +15,18 @@ import (
// CreateFeed is the API handler to create a new feed.
func (c *Controller) CreateFeed(w http.ResponseWriter, r *http.Request) {
- feedURL, categoryID, err := decodeFeedCreationPayload(r.Body)
+ feedInfo, err := decodeFeedCreationPayload(r.Body)
if err != nil {
json.BadRequest(w, err)
return
}
- if feedURL == "" {
+ if feedInfo.FeedURL == "" {
json.BadRequest(w, errors.New("The feed_url is required"))
return
}
- if categoryID <= 0 {
+ if feedInfo.CategoryID <= 0 {
json.BadRequest(w, errors.New("The category_id is required"))
return
}
@@ -34,17 +34,24 @@ func (c *Controller) CreateFeed(w http.ResponseWriter, r *http.Request) {
ctx := context.New(r)
userID := ctx.UserID()
- if c.store.FeedURLExists(userID, feedURL) {
+ if c.store.FeedURLExists(userID, feedInfo.FeedURL) {
json.BadRequest(w, errors.New("This feed_url already exists"))
return
}
- if !c.store.CategoryExists(userID, categoryID) {
+ if !c.store.CategoryExists(userID, feedInfo.CategoryID) {
json.BadRequest(w, errors.New("This category_id doesn't exists or doesn't belongs to this user"))
return
}
- feed, err := c.feedHandler.CreateFeed(userID, categoryID, feedURL, false)
+ feed, err := c.feedHandler.CreateFeed(
+ userID,
+ feedInfo.CategoryID,
+ feedInfo.FeedURL,
+ feedInfo.Crawler,
+ feedInfo.Username,
+ feedInfo.Password,
+ )
if err != nil {
json.ServerError(w, errors.New("Unable to create this feed"))
return
diff --git a/api/payload.go b/api/payload.go
index bf470eb..45cb826 100644
--- a/api/payload.go
+++ b/api/payload.go
@@ -23,6 +23,20 @@ type entriesResponse struct {
Entries model.Entries `json:"entries"`
}
+type feedCreation struct {
+ FeedURL string `json:"feed_url"`
+ CategoryID int64 `json:"category_id"`
+ Username string `json:"username"`
+ Password string `json:"password"`
+ Crawler bool `json:"crawler"`
+}
+
+type subscriptionDiscovery struct {
+ URL string `json:"url"`
+ Username string `json:"username"`
+ Password string `json:"password"`
+}
+
func decodeUserPayload(r io.ReadCloser) (*model.User, error) {
var user model.User
@@ -35,19 +49,16 @@ func decodeUserPayload(r io.ReadCloser) (*model.User, error) {
return &user, nil
}
-func decodeURLPayload(r io.ReadCloser) (string, error) {
- type payload struct {
- URL string `json:"url"`
- }
+func decodeURLPayload(r io.ReadCloser) (*subscriptionDiscovery, error) {
+ defer r.Close()
- var p payload
+ var s subscriptionDiscovery
decoder := json.NewDecoder(r)
- defer r.Close()
- if err := decoder.Decode(&p); err != nil {
- return "", fmt.Errorf("invalid JSON payload: %v", err)
+ if err := decoder.Decode(&s); err != nil {
+ return nil, fmt.Errorf("invalid JSON payload: %v", err)
}
- return p.URL, nil
+ return &s, nil
}
func decodeEntryStatusPayload(r io.ReadCloser) ([]int64, string, error) {
@@ -66,20 +77,16 @@ func decodeEntryStatusPayload(r io.ReadCloser) ([]int64, string, error) {
return p.EntryIDs, p.Status, nil
}
-func decodeFeedCreationPayload(r io.ReadCloser) (string, int64, error) {
- type payload struct {
- FeedURL string `json:"feed_url"`
- CategoryID int64 `json:"category_id"`
- }
+func decodeFeedCreationPayload(r io.ReadCloser) (*feedCreation, error) {
+ defer r.Close()
- var p payload
+ var fc feedCreation
decoder := json.NewDecoder(r)
- defer r.Close()
- if err := decoder.Decode(&p); err != nil {
- return "", 0, fmt.Errorf("invalid JSON payload: %v", err)
+ if err := decoder.Decode(&fc); err != nil {
+ return nil, fmt.Errorf("invalid JSON payload: %v", err)
}
- return p.FeedURL, p.CategoryID, nil
+ return &fc, nil
}
func decodeFeedModificationPayload(r io.ReadCloser) (*model.Feed, error) {
diff --git a/api/subscription.go b/api/subscription.go
index c858f0e..19adc9e 100644
--- a/api/subscription.go
+++ b/api/subscription.go
@@ -15,13 +15,17 @@ import (
// GetSubscriptions is the API handler to find subscriptions.
func (c *Controller) GetSubscriptions(w http.ResponseWriter, r *http.Request) {
- websiteURL, err := decodeURLPayload(r.Body)
+ subscriptionInfo, err := decodeURLPayload(r.Body)
if err != nil {
json.BadRequest(w, err)
return
}
- subscriptions, err := subscription.FindSubscriptions(websiteURL)
+ subscriptions, err := subscription.FindSubscriptions(
+ subscriptionInfo.URL,
+ subscriptionInfo.Username,
+ subscriptionInfo.Password,
+ )
if err != nil {
json.ServerError(w, errors.New("Unable to discover subscriptions"))
return
diff --git a/http/client/client.go b/http/client/client.go
index 60ebbc7..d808a70 100644
--- a/http/client/client.go
+++ b/http/client/client.go
@@ -52,8 +52,10 @@ type Client struct {
// WithCredentials defines the username/password for HTTP Basic authentication.
func (c *Client) WithCredentials(username, password string) *Client {
- c.username = username
- c.password = password
+ if username != "" && password != "" {
+ c.username = username
+ c.password = password
+ }
return c
}
@@ -159,7 +161,7 @@ func (c *Client) executeRequest(request *http.Request) (*Response, error) {
ContentLength: resp.ContentLength,
}
- logger.Debug("[HttpClient:%s] URL=%s, EffectiveURL=%s, Code=%d, Length=%d, Type=%s, ETag=%s, LastMod=%s, Expires=%s",
+ logger.Debug("[HttpClient:%s] URL=%s, EffectiveURL=%s, Code=%d, Length=%d, Type=%s, ETag=%s, LastMod=%s, Expires=%s, Auth=%v",
request.Method,
c.url,
response.EffectiveURL,
@@ -169,6 +171,7 @@ func (c *Client) executeRequest(request *http.Request) (*Response, error) {
response.ETag,
response.LastModified,
resp.Header.Get("Expires"),
+ c.username != "",
)
// Ignore caching headers for feeds that do not want any cache.
diff --git a/locale/translations.go b/locale/translations.go
index e6f9b85..047ec89 100755
--- a/locale/translations.go
+++ b/locale/translations.go
@@ -1,5 +1,5 @@
// Code generated by go generate; DO NOT EDIT.
-// 2018-06-05 15:34:49.597679681 +0200 CEST m=+0.259287761
+// 2018-06-19 22:56:40.321373022 -0700 PDT m=+0.043185142
package locale
@@ -479,7 +479,10 @@ var translations = map[string]string{
"Pocket Access Token": "« Pocket Access Token »",
"Your Pocket account is now linked!": "Votre compte Pocket est maintenant connecté !",
"Unable to fetch access token from Pocket!": "Impossible de récupérer le jeton d'accès depuis Pocket !",
- "Unable to fetch request token from Pocket!": "Impossible de récupérer le jeton d'accès depuis Pocket !"
+ "Unable to fetch request token from Pocket!": "Impossible de récupérer le jeton d'accès depuis Pocket !",
+ "Advanced Options": "Options avancées",
+ "Feed Username": "Nom d'utilisateur du flux",
+ "Feed Password": "Mot de passe du flux"
}
`,
"nl_NL": `{
@@ -1154,7 +1157,7 @@ var translations = map[string]string{
var translationsChecksums = map[string]string{
"de_DE": "c6b06d144a57719194bc71da5911fee14659d77bb3deae7f3d6c28d1e019d366",
"en_US": "6fe95384260941e8a5a3c695a655a932e0a8a6a572c1e45cb2b1ae8baa01b897",
- "fr_FR": "808f1561135bb3d0f886833f00a51402113925e9086c01f71b30bcc679d9b7c2",
+ "fr_FR": "734b9ee6edc65e5c076fc91999d81f6c586eeb52f420101049bff9b501cbae54",
"nl_NL": "1a73f1dd1c4c0d2c2adc8695cdd050c2dad81c14876caed3892b44adc2491265",
"pl_PL": "da709c14ff71f3b516eec66cb2758d89c5feab1472c94b2b518f425162a9f806",
"zh_CN": "d80594c1b67d15e9f4673d3d62fe4949e8606a5fdfb741d8a8921f21dceb8cf2",
diff --git a/locale/translations/fr_FR.json b/locale/translations/fr_FR.json
index 6d66f11..4c830b4 100644
--- a/locale/translations/fr_FR.json
+++ b/locale/translations/fr_FR.json
@@ -229,5 +229,8 @@
"Pocket Access Token": "« Pocket Access Token »",
"Your Pocket account is now linked!": "Votre compte Pocket est maintenant connecté !",
"Unable to fetch access token from Pocket!": "Impossible de récupérer le jeton d'accès depuis Pocket !",
- "Unable to fetch request token from Pocket!": "Impossible de récupérer le jeton d'accès depuis Pocket !"
+ "Unable to fetch request token from Pocket!": "Impossible de récupérer le jeton d'accès depuis Pocket !",
+ "Advanced Options": "Options avancées",
+ "Feed Username": "Nom d'utilisateur du flux",
+ "Feed Password": "Mot de passe du flux"
}
diff --git a/model/feed.go b/model/feed.go
index c2ee6e8..9c7ecca 100644
--- a/model/feed.go
+++ b/model/feed.go
@@ -24,6 +24,8 @@ type Feed struct {
ScraperRules string `json:"scraper_rules"`
RewriteRules string `json:"rewrite_rules"`
Crawler bool `json:"crawler"`
+ Username string `json:"username"`
+ Password string `json:"password"`
Category *Category `json:"category,omitempty"`
Entries Entries `json:"entries,omitempty"`
Icon *FeedIcon `json:"icon"`
@@ -69,6 +71,14 @@ func (f *Feed) Merge(override *Feed) {
if override.Category != nil && override.Category.ID != 0 && override.Category.ID != f.Category.ID {
f.Category.ID = override.Category.ID
}
+
+ if override.Username != f.Username {
+ f.Username = override.Username
+ }
+
+ if override.Password != f.Password {
+ f.Password = override.Password
+ }
}
// Feeds is a list of feed
diff --git a/reader/feed/handler.go b/reader/feed/handler.go
index 4b50820..24fdadf 100644
--- a/reader/feed/handler.go
+++ b/reader/feed/handler.go
@@ -36,7 +36,7 @@ type Handler struct {
}
// CreateFeed fetch, parse and store a new feed.
-func (h *Handler) CreateFeed(userID, categoryID int64, url string, crawler bool) (*model.Feed, error) {
+func (h *Handler) CreateFeed(userID, categoryID int64, url string, crawler bool, username, password string) (*model.Feed, error) {
defer timer.ExecutionTime(time.Now(), fmt.Sprintf("[Handler:CreateFeed] feedUrl=%s", url))
if !h.store.CategoryExists(userID, categoryID) {
@@ -44,6 +44,7 @@ func (h *Handler) CreateFeed(userID, categoryID int64, url string, crawler bool)
}
clt := client.New(url)
+ clt.WithCredentials(username, password)
response, err := clt.Get()
if err != nil {
if _, ok := err.(*errors.LocalizedError); ok {
@@ -85,6 +86,8 @@ func (h *Handler) CreateFeed(userID, categoryID int64, url string, crawler bool)
subscription.FeedURL = response.EffectiveURL
subscription.UserID = userID
subscription.Crawler = crawler
+ subscription.Username = username
+ subscription.Password = password
if subscription.SiteURL == "" {
subscription.SiteURL = subscription.FeedURL
@@ -130,6 +133,7 @@ func (h *Handler) RefreshFeed(userID, feedID int64) error {
}
clt := client.New(originalFeed.FeedURL)
+ clt.WithCredentials(originalFeed.Username, originalFeed.Password)
clt.WithCacheHeaders(originalFeed.EtagHeader, originalFeed.LastModifiedHeader)
response, err := clt.Get()
if err != nil {
diff --git a/reader/subscription/finder.go b/reader/subscription/finder.go
index e5a27f5..6b45cfb 100644
--- a/reader/subscription/finder.go
+++ b/reader/subscription/finder.go
@@ -27,10 +27,11 @@ var (
)
// FindSubscriptions downloads and try to find one or more subscriptions from an URL.
-func FindSubscriptions(websiteURL string) (Subscriptions, error) {
+func FindSubscriptions(websiteURL, username, password string) (Subscriptions, error) {
defer timer.ExecutionTime(time.Now(), fmt.Sprintf("[FindSubscriptions] url=%s", websiteURL))
clt := client.New(websiteURL)
+ clt.WithCredentials(username, password)
response, err := clt.Get()
if err != nil {
if _, ok := err.(errors.LocalizedError); ok {
diff --git a/sql/schema_version_19.sql b/sql/schema_version_19.sql
new file mode 100644
index 0000000..130ae08
--- /dev/null
+++ b/sql/schema_version_19.sql
@@ -0,0 +1,2 @@
+alter table feeds add column username text default '';
+alter table feeds add column password text default ''; \ No newline at end of file
diff --git a/sql/sql.go b/sql/sql.go
index 9529b02..d095893 100644
--- a/sql/sql.go
+++ b/sql/sql.go
@@ -1,5 +1,5 @@
// Code generated by go generate; DO NOT EDIT.
-// 2018-05-21 12:33:12.475674107 -0700 PDT m=+0.003076147
+// 2018-06-19 22:56:40.283528941 -0700 PDT m=+0.005341061
package sql
@@ -136,6 +136,8 @@ alter table integrations add column pocket_access_token text default '';
alter table integrations add column pocket_consumer_key text default '';
`,
"schema_version_18": `alter table user_sessions alter column ip set data type inet using ip::inet;`,
+ "schema_version_19": `alter table feeds add column username text default '';
+alter table feeds add column password text default '';`,
"schema_version_2": `create extension if not exists hstore;
alter table users add column extra hstore;
create index users_extra_idx on users using gin(extra);
@@ -185,6 +187,7 @@ var SqlMapChecksums = map[string]string{
"schema_version_16": "9d006faca62fd7ab787f64aef0e0a5933d142466ec4cab0e096bb920d2797e34",
"schema_version_17": "b9f15d6217275fedcf6d948dd85ebe978b869bf37f42a86fd5b50a51919fa0e1",
"schema_version_18": "c0ec24847612c7f2dc326cf735baffba79391a56aedd73292371a39f38724a71",
+ "schema_version_19": "a83f77b41cc213d282805a5b518f15abbf96331599119f0ef4aca4be037add7b",
"schema_version_2": "e8e9ff32478df04fcddad10a34cba2e8bb1e67e7977b5bd6cdc4c31ec94282b4",
"schema_version_3": "a54745dbc1c51c000f74d4e5068f1e2f43e83309f023415b1749a47d5c1e0f12",
"schema_version_4": "216ea3a7d3e1704e40c797b5dc47456517c27dbb6ca98bf88812f4f63d74b5d9",
diff --git a/storage/feed.go b/storage/feed.go
index 7aa78b0..4c0a630 100644
--- a/storage/feed.go
+++ b/storage/feed.go
@@ -56,6 +56,7 @@ func (s *Storage) Feeds(userID int64) (model.Feeds, error) {
f.user_id, f.checked_at at time zone u.timezone,
f.parsing_error_count, f.parsing_error_msg,
f.scraper_rules, f.rewrite_rules, f.crawler,
+ f.username, f.password,
f.category_id, c.title as category_title,
fi.icon_id,
u.timezone
@@ -92,6 +93,8 @@ func (s *Storage) Feeds(userID int64) (model.Feeds, error) {
&feed.ScraperRules,
&feed.RewriteRules,
&feed.Crawler,
+ &feed.Username,
+ &feed.Password,
&feed.Category.ID,
&feed.Category.Title,
&iconID,
@@ -128,6 +131,7 @@ func (s *Storage) FeedByID(userID, feedID int64) (*model.Feed, error) {
f.user_id, f.checked_at at time zone u.timezone,
f.parsing_error_count, f.parsing_error_msg,
f.scraper_rules, f.rewrite_rules, f.crawler,
+ f.username, f.password,
f.category_id, c.title as category_title,
fi.icon_id,
u.timezone
@@ -151,6 +155,8 @@ func (s *Storage) FeedByID(userID, feedID int64) (*model.Feed, error) {
&feed.ScraperRules,
&feed.RewriteRules,
&feed.Crawler,
+ &feed.Username,
+ &feed.Password,
&feed.Category.ID,
&feed.Category.Title,
&iconID,
@@ -177,8 +183,8 @@ func (s *Storage) CreateFeed(feed *model.Feed) error {
defer timer.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:CreateFeed] feedURL=%s", feed.FeedURL))
sql := `
INSERT INTO feeds
- (feed_url, site_url, title, category_id, user_id, etag_header, last_modified_header, crawler)
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
+ (feed_url, site_url, title, category_id, user_id, etag_header, last_modified_header, crawler, username, password)
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
RETURNING id
`
@@ -192,6 +198,8 @@ func (s *Storage) CreateFeed(feed *model.Feed) error {
feed.EtagHeader,
feed.LastModifiedHeader,
feed.Crawler,
+ feed.Username,
+ feed.Password,
).Scan(&feed.ID)
if err != nil {
return fmt.Errorf("unable to create feed: %v", err)
@@ -215,8 +223,9 @@ func (s *Storage) UpdateFeed(feed *model.Feed) (err error) {
query := `UPDATE feeds SET
feed_url=$1, site_url=$2, title=$3, category_id=$4, etag_header=$5, last_modified_header=$6, checked_at=$7,
- parsing_error_msg=$8, parsing_error_count=$9, scraper_rules=$10, rewrite_rules=$11, crawler=$12
- WHERE id=$13 AND user_id=$14`
+ parsing_error_msg=$8, parsing_error_count=$9, scraper_rules=$10, rewrite_rules=$11, crawler=$12,
+ username=$13, password=$14
+ WHERE id=$15 AND user_id=$16`
_, err = s.db.Exec(query,
feed.FeedURL,
@@ -231,6 +240,8 @@ func (s *Storage) UpdateFeed(feed *model.Feed) (err error) {
feed.ScraperRules,
feed.RewriteRules,
feed.Crawler,
+ feed.Username,
+ feed.Password,
feed.ID,
feed.UserID,
)
diff --git a/storage/migration.go b/storage/migration.go
index 097c526..56b7bfb 100644
--- a/storage/migration.go
+++ b/storage/migration.go
@@ -12,7 +12,7 @@ import (
"github.com/miniflux/miniflux/sql"
)
-const schemaVersion = 18
+const schemaVersion = 19
// Migrate run database migrations.
func (s *Storage) Migrate() {
diff --git a/template/common.go b/template/common.go
index 986e0a2..15b144c 100644
--- a/template/common.go
+++ b/template/common.go
@@ -1,5 +1,5 @@
// Code generated by go generate; DO NOT EDIT.
-// 2018-05-21 12:40:10.613112 +0200 CEST m=+0.010961753
+// 2018-06-19 22:56:40.319198468 -0700 PDT m=+0.041010588
package template
diff --git a/template/html/add_subscription.html b/template/html/add_subscription.html
index b65dabb..bff7975 100644
--- a/template/html/add_subscription.html
+++ b/template/html/add_subscription.html
@@ -36,7 +36,17 @@
{{ end }}
</select>
- <label><input type="checkbox" name="crawler" value="1" {{ if .form.Crawler }}checked{{ end }}> {{ t "Fetch original content" }}</label>
+ <fieldset>
+ <legend>{{ t "Advanced Options" }}</legend>
+
+ <label><input type="checkbox" name="crawler" value="1" {{ if .form.Crawler }}checked{{ end }}> {{ t "Fetch original content" }}</label>
+
+ <label for="form-username">{{ t "Feed Username" }}</label>
+ <input type="text" name="username" id="form-username" value="{{ .form.Username }}">
+
+ <label for="form-password">{{ t "Feed Password" }}</label>
+ <input type="password" name="password" id="form-password" value="{{ .form.Password }}">
+ </fieldset>
<div class="buttons">
<button type="submit" class="button button-primary" data-label-loading="{{ t "Loading..." }}">{{ t "Find a subscription" }}</button>
diff --git a/template/html/choose_subscription.html b/template/html/choose_subscription.html
index a1a8e68..7668605 100644
--- a/template/html/choose_subscription.html
+++ b/template/html/choose_subscription.html
@@ -18,7 +18,12 @@
<form action="{{ route "chooseSubscription" }}" method="POST">
<input type="hidden" name="csrf" value="{{ .csrf }}">
- <input type="hidden" name="category_id" value="{{ .categoryID }}">
+ <input type="hidden" name="category_id" value="{{ .form.CategoryID }}">
+ <input type="hidden" name="username" value="{{ .form.Username }}">
+ <input type="hidden" name="password" value="{{ .form.Password }}">
+ {{ if .form.Crawler }}
+ <input type="hidden" name="crawler" value="1">
+ {{ end }}
<h3>{{ t "Choose a Subscription" }}</h3>
@@ -29,9 +34,6 @@
</div>
{{ end }}
- <br>
- <label><input type="checkbox" name="crawler" value="1" {{ if .form.Crawler }}checked{{ end }}> {{ t "Fetch original content" }}</label>
-
<div class="buttons">
<button type="submit" class="button button-primary" data-label-loading="{{ t "Loading..." }}">{{ t "Subscribe" }}</button>
</div>
diff --git a/template/html/edit_feed.html b/template/html/edit_feed.html
index e5bb60a..704472b 100644
--- a/template/html/edit_feed.html
+++ b/template/html/edit_feed.html
@@ -45,6 +45,12 @@
<label for="form-feed-url">{{ t "Feed URL" }}</label>
<input type="url" name="feed_url" id="form-feed-url" placeholder="https://domain.tld/" value="{{ .form.FeedURL }}" required>
+ <label for="form-username">{{ t "Feed Username" }}</label>
+ <input type="text" name="username" id="form-username" value="{{ .form.Username }}">
+
+ <label for="form-password">{{ t "Feed Password" }}</label>
+ <input type="password" name="password" id="form-password" value="{{ .form.Password }}">
+
<label for="form-scraper-rules">{{ t "Scraper Rules" }}</label>
<input type="text" name="scraper_rules" id="form-scraper-rules" value="{{ .form.ScraperRules }}">
diff --git a/template/views.go b/template/views.go
index 27297bb..30c9dad 100644
--- a/template/views.go
+++ b/template/views.go
@@ -1,5 +1,5 @@
// Code generated by go generate; DO NOT EDIT.
-// 2018-05-21 12:14:59.39668234 -0700 PDT m=+0.007850936
+// 2018-06-19 22:56:40.310658103 -0700 PDT m=+0.032470223
package template
@@ -83,7 +83,17 @@ var templateViewsMap = map[string]string{
{{ end }}
</select>
- <label><input type="checkbox" name="crawler" value="1" {{ if .form.Crawler }}checked{{ end }}> {{ t "Fetch original content" }}</label>
+ <fieldset>
+ <legend>{{ t "Advanced Options" }}</legend>
+
+ <label><input type="checkbox" name="crawler" value="1" {{ if .form.Crawler }}checked{{ end }}> {{ t "Fetch original content" }}</label>
+
+ <label for="form-username">{{ t "Feed Username" }}</label>
+ <input type="text" name="username" id="form-username" value="{{ .form.Username }}">
+
+ <label for="form-password">{{ t "Feed Password" }}</label>
+ <input type="password" name="password" id="form-password" value="{{ .form.Password }}">
+ </fieldset>
<div class="buttons">
<button type="submit" class="button button-primary" data-label-loading="{{ t "Loading..." }}">{{ t "Find a subscription" }}</button>
@@ -239,7 +249,12 @@ var templateViewsMap = map[string]string{
<form action="{{ route "chooseSubscription" }}" method="POST">
<input type="hidden" name="csrf" value="{{ .csrf }}">
- <input type="hidden" name="category_id" value="{{ .categoryID }}">
+ <input type="hidden" name="category_id" value="{{ .form.CategoryID }}">
+ <input type="hidden" name="username" value="{{ .form.Username }}">
+ <input type="hidden" name="password" value="{{ .form.Password }}">
+ {{ if .form.Crawler }}
+ <input type="hidden" name="crawler" value="1">
+ {{ end }}
<h3>{{ t "Choose a Subscription" }}</h3>
@@ -250,9 +265,6 @@ var templateViewsMap = map[string]string{
</div>
{{ end }}
- <br>
- <label><input type="checkbox" name="crawler" value="1" {{ if .form.Crawler }}checked{{ end }}> {{ t "Fetch original content" }}</label>
-
<div class="buttons">
<button type="submit" class="button button-primary" data-label-loading="{{ t "Loading..." }}">{{ t "Subscribe" }}</button>
</div>
@@ -413,6 +425,12 @@ var templateViewsMap = map[string]string{
<label for="form-feed-url">{{ t "Feed URL" }}</label>
<input type="url" name="feed_url" id="form-feed-url" placeholder="https://domain.tld/" value="{{ .form.FeedURL }}" required>
+ <label for="form-username">{{ t "Feed Username" }}</label>
+ <input type="text" name="username" id="form-username" value="{{ .form.Username }}">
+
+ <label for="form-password">{{ t "Feed Password" }}</label>
+ <input type="password" name="password" id="form-password" value="{{ .form.Password }}">
+
<label for="form-scraper-rules">{{ t "Scraper Rules" }}</label>
<input type="text" name="scraper_rules" id="form-scraper-rules" value="{{ .form.ScraperRules }}">
@@ -1250,15 +1268,15 @@ var templateViewsMap = map[string]string{
var templateViewsMapChecksums = map[string]string{
"about": "ad2fb778fc73c39b733b3f81b13e5c7d689b041fadd24ee2d4577f545aa788ad",
- "add_subscription": "053c920b0d7e109ea19dce6a448e304ce720db8633588ea04db16677f7209a7b",
+ "add_subscription": "5067776ce452543fceed8b62defe5fbfed41e3d5bd79b5f2acf8c45ef4faac6d",
"bookmark_entries": "8e5fea7559218a34289c2f0e54955fc0ef3b9e629205927841cbcc2276aefb2a",
"categories": "ca1280cd157bb527d4fc907da67b05a8347378f6dce965b9389d4bcdf3600a11",
"category_entries": "6ad52c8d0c28e21ea48be76228ea8432adde1dc190010753a48928477d52e065",
- "choose_subscription": "a325f9c976ca2b2dc148e25c8fef0cf6ccab0e04e86e604e7812bb18dc4cdde1",
+ "choose_subscription": "c680e690255d53da1f4f11e9b997bc2a32ca659f1245076e5738243859e17876",
"create_category": "2b82af5d2dcd67898dc5daa57a6461e6ff8121a6089b2a2a1be909f35e4a2275",
"create_user": "233764778c915754141a20429ec8db9bf80ef2d7704867a2d7232c1e9df233ae",
"edit_category": "cee720faadcec58289b707ad30af623d2ee66c1ce23a732965463250d7ff41c5",
- "edit_feed": "d2c1c8486d7faf4ee58151ccf3e3c690e53bd6872050d291c5db8452a83c3d53",
+ "edit_feed": "66dd3ca6357645944a99f8b9c0455253e6d2bf5f36faf9aa322689b6299b0104",
"edit_user": "321e0a60cf3bf7441bff970f4920e4c5b7c1883f80ab1d1674f8137954b25033",
"entry": "bd611521ebb46714fce434fe7fa5d4e53e50da4c3ed02450ad3557f614f16e14",
"feed_entries": "4dffdb55cfad29df20612efe7ed2dbed03d919c4556898543ab6450f610d3c99",
diff --git a/ui/feed_edit.go b/ui/feed_edit.go
index d6062c8..3a4e862 100644
--- a/ui/feed_edit.go
+++ b/ui/feed_edit.go
@@ -56,6 +56,8 @@ func (c *Controller) EditFeed(w http.ResponseWriter, r *http.Request) {
RewriteRules: feed.RewriteRules,
Crawler: feed.Crawler,
CategoryID: feed.Category.ID,
+ Username: feed.Username,
+ Password: feed.Password,
}
sess := session.New(c.store, ctx)
diff --git a/ui/form/feed.go b/ui/form/feed.go
index 896a6d7..1a3766b 100644
--- a/ui/form/feed.go
+++ b/ui/form/feed.go
@@ -21,6 +21,8 @@ type FeedForm struct {
RewriteRules string
Crawler bool
CategoryID int64
+ Username string
+ Password string
}
// ValidateModification validates FeedForm fields
@@ -42,6 +44,8 @@ func (f FeedForm) Merge(feed *model.Feed) *model.Feed {
feed.Crawler = f.Crawler
feed.ParsingErrorCount = 0
feed.ParsingErrorMsg = ""
+ feed.Username = f.Username
+ feed.Password = f.Password
return feed
}
@@ -60,5 +64,7 @@ func NewFeedForm(r *http.Request) *FeedForm {
RewriteRules: r.FormValue("rewrite_rules"),
Crawler: r.FormValue("crawler") == "1",
CategoryID: int64(categoryID),
+ Username: r.FormValue("username"),
+ Password: r.FormValue("password"),
}
}
diff --git a/ui/form/subscription.go b/ui/form/subscription.go
index 7d2caaf..015f60f 100644
--- a/ui/form/subscription.go
+++ b/ui/form/subscription.go
@@ -16,6 +16,8 @@ type SubscriptionForm struct {
URL string
CategoryID int64
Crawler bool
+ Username string
+ Password string
}
// Validate makes sure the form values are valid.
@@ -38,5 +40,7 @@ func NewSubscriptionForm(r *http.Request) *SubscriptionForm {
URL: r.FormValue("url"),
Crawler: r.FormValue("crawler") == "1",
CategoryID: int64(categoryID),
+ Username: r.FormValue("username"),
+ Password: r.FormValue("password"),
}
}
diff --git a/ui/static/bin.go b/ui/static/bin.go
index 6c74cd9..3cb9157 100644
--- a/ui/static/bin.go
+++ b/ui/static/bin.go
@@ -1,5 +1,5 @@
// Code generated by go generate; DO NOT EDIT.
-// 2018-05-20 15:22:33.779971968 -0700 PDT m=+0.011442481
+// 2018-06-19 22:56:40.300982018 -0700 PDT m=+0.022794138
package static
diff --git a/ui/static/css.go b/ui/static/css.go
index 831a701..1d8cc72 100644
--- a/ui/static/css.go
+++ b/ui/static/css.go
@@ -1,16 +1,16 @@
// Code generated by go generate; DO NOT EDIT.
-// 2018-06-19 00:54:40.204433682 -0400 EDT m=+0.004478068
+// 2018-06-19 22:56:40.306263546 -0700 PDT m=+0.028075666
package static
var Stylesheets = map[string]string{
"black": `body{background:#222;color:#efefef}h1,h2,h3{color:#aaa}a{color:#aaa}a:focus,a:hover{color:#ddd}.header li{border-color:#333}.header a{color:#ddd;font-weight:400}.header .active a{font-weight:400;color:#9b9494}.header a:focus,.header a:hover{color:rgba(82,168,236,.85)}.page-header h1{border-color:#333}.logo a:hover span{color:#555}table,th,td{border:1px solid #555}th{background:#333;color:#aaa;font-weight:400}tr:hover{background-color:#333;color:#aaa}input[type=url],input[type=password],input[type=text]{border:1px solid #555;background:#333;color:#ccc}input[type=url]:focus,input[type=password]:focus,input[type=text]:focus{color:#efefef;border-color:rgba(82,168,236,.8);box-shadow:0 0 8px rgba(82,168,236,.6)}.button-primary{border-color:#444;background:#333;color:#efefef}.button-primary:hover,.button-primary:focus{border-color:#888;background:#555}.alert,.alert-success,.alert-error,.alert-info,.alert-normal{color:#efefef;background-color:#333;border-color:#444}.panel{background:#333;border-color:#555;color:#9b9b9b}#modal-left{background:#333;color:#efefef;box-shadow:0 0 10px rgba(82,168,236,.6)}.keyboard-shortcuts li{color:#9b9b9b}.unread-counter-wrapper{color:#bbb}.category{color:#efefef;background-color:#333;border-color:#444}.category a{color:#999}.category a:hover,.category a:focus{color:#aaa}.pagination a{color:#aaa}.pagination-bottom{border-color:#333}.item{border-color:#666;padding:4px}.item.current-item{border-width:2px;border-color:rgba(82,168,236,.8);box-shadow:0 0 8px rgba(82,168,236,.6)}.item-title a{font-weight:400}.item-status-read .item-title a{color:#666}.item-status-read .item-title a:focus,.item-status-read .item-title a:hover{color:rgba(82,168,236,.6)}.item-meta a:hover,.item-meta a:focus{color:#aaa}.item-meta li:after{color:#ddd}article.feed-parsing-error{background-color:#343434}.parsing-error{color:#eee}.entry header{border-color:#333}.entry header h1 a{color:#bbb}.entry-content,.entry-content p,ul{color:#999}.entry-content pre,.entry-content code{color:#fff;background:#555;border-color:#888}.entry-content q{color:#777}.entry-enclosure{border-color:#333}`,
- "common": `*{margin:0;padding:0;box-sizing:border-box}body{font-family:helvetica neue,Helvetica,Arial,sans-serif;text-rendering:optimizeLegibility}main{padding-left:5px;padding-right:5px;margin-bottom:30px}a{color:#36c}a:focus{outline:0;color:red;text-decoration:none;border:1px dotted #aaa}a:hover{color:#333;text-decoration:none}.header{margin-top:10px;margin-bottom:20px}.header nav ul{display:none}.header li{cursor:pointer;padding-left:10px;line-height:2.1em;font-size:1.2em;border-bottom:1px dotted #ddd}.header li:hover a{color:#888}.header a{font-size:.9em;color:#444;text-decoration:none;border:0}.header .active a{font-weight:600}.header a:hover,.header a:focus{color:#888}.page-header{margin-bottom:25px}.page-header h1{font-weight:500;border-bottom:1px dotted #ddd}.page-header ul{margin-left:25px}.page-header li{list-style-type:circle;line-height:1.8em}.logo{cursor:pointer;text-align:center}.logo a{color:#000;letter-spacing:1px}.logo a:hover{color:#396}.logo a span{color:#396}.logo a:hover span{color:#000}@media(min-width:600px){body{margin:auto;max-width:750px}.logo{text-align:left;float:left;margin-right:15px}.header nav ul{display:block}.header li{display:inline;padding:0;padding-right:15px;line-height:normal;border:0;font-size:1em}.page-header ul{margin-left:0}.page-header li{display:inline;padding-right:15px}}table{width:100%;border-collapse:collapse}table,th,td{border:1px solid #ddd}th,td{padding:5px;text-align:left}td{vertical-align:top}th{background:#fcfcfc}tr:hover{background-color:#f9f9f9}.column-40{width:40%}.column-25{width:25%}.column-20{width:20%}label{cursor:pointer;display:block}.radio-group{line-height:1.9em}div.radio-group label{display:inline-block}select{margin-bottom:15px}input[type=url],input[type=password],input[type=text]{border:1px solid #ccc;padding:3px;line-height:20px;width:250px;font-size:99%;margin-bottom:10px;margin-top:5px;-webkit-appearance:none}input[type=url]:focus,input[type=password]:focus,input[type=text]:focus{color:#000;border-color:rgba(82,168,236,.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,.6)}input[type=checkbox]{margin-bottom:15px}::-moz-placeholder,::-ms-input-placeholder,::-webkit-input-placeholder{color:#ddd;padding-top:2px}.form-help{font-size:.9em;color:brown;margin-bottom:15px}.form-section{border-left:2px dotted #ddd;padding-left:20px;margin-left:10px}a.button{text-decoration:none}.button{display:inline-block;-webkit-appearance:none;-moz-appearance:none;font-size:1.1em;cursor:pointer;padding:3px 10px;border:1px solid;border-radius:unset}.button-primary{border-color:#3079ed;background:#4d90fe;color:#fff}.button-primary:hover,.button-primary:focus{border-color:#2f5bb7;background:#357ae8}.button-danger{border-color:#b0281a;background:#d14836;color:#fff}.button-danger:hover,.button-danger:focus{color:#fff;background:#c53727}.button:disabled{color:#ccc;background:#f7f7f7;border-color:#ccc}.buttons{margin-top:10px;margin-bottom:20px}.alert{padding:8px 35px 8px 14px;margin-bottom:20px;color:#c09853;background-color:#fcf8e3;border:1px solid #fbeed5;border-radius:4px;overflow:auto}.alert h3{margin-top:0;margin-bottom:15px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-error a{color:#b94a48}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.panel{color:#333;background-color:#fcfcfc;border:1px solid #ddd;border-radius:5px;padding:10px;margin-bottom:15px}.panel h3{font-weight:500;margin-top:0;margin-bottom:20px}.panel ul{margin-left:30px}#modal-left{position:fixed;top:0;left:0;bottom:0;width:350px;overflow:auto;background:#f0f0f0;box-shadow:2px 0 5px 0 #ccc;padding:5px;padding-top:30px}#modal-left h3{font-weight:400}.btn-close-modal{position:absolute;top:0;right:0;font-size:1.7em;color:#ccc;padding:0 .2em;margin:10px;text-decoration:none}.btn-close-modal:hover{color:#999}.keyboard-shortcuts li{margin-left:25px;list-style-type:square;color:#333;font-size:.95em;line-height:1.45em}.keyboard-shortcuts p{line-height:1.9em}.login-form{margin:50px auto 0;max-width:280px}.unread-counter-wrapper{font-size:.9em;font-weight:300;color:#666}.category{font-size:.75em;background-color:#fffcd7;border:1px solid #d5d458;border-radius:5px;margin-left:.25em;padding:1px .4em;white-space:nowrap}.category a{color:#555;text-decoration:none}.category a:hover,.category a:focus{color:#000}.pagination{font-size:1.1em;display:flex;align-items:center;padding-top:8px}.pagination-bottom{border-top:1px dotted #ddd;margin-bottom:15px;margin-top:50px}.pagination>div{flex:1}.pagination-next{text-align:right}.pagination-prev:before{content:"« "}.pagination-next:after{content:" »"}.pagination a{color:#333}.pagination a:hover,.pagination a:focus{text-decoration:none}.item{border:1px dotted #ddd;margin-bottom:20px;padding:5px;overflow:hidden}.item.current-item{border:3px solid #bce;padding:3px}.item-title a{text-decoration:none;font-weight:600}.item-status-read .item-title a{color:#777}.item-meta{color:#777;font-size:.8em}.item-meta a{color:#777;text-decoration:none}.item-meta a:hover,.item-meta a:focus{color:#333}.item-meta ul{margin-top:5px}.item-meta li{display:inline}.item-meta li:after{content:"|";color:#aaa}.item-meta li:last-child:after{content:""}.items{overflow-x:hidden}.hide-read-items .item-status-read{display:none}article.feed-parsing-error{background-color:#fcf8e3;border-color:#aaa}.parsing-error{font-size:.85em;margin-top:2px;color:#333}.parsing-error-count{cursor:pointer}.entry header{padding-bottom:5px;border-bottom:1px dotted #ddd}.entry header h1{font-size:2em;line-height:1.25em;margin:30px 0}.entry header h1 a{text-decoration:none;color:#333}.entry header h1 a:hover,.entry header h1 a:focus{color:#666}.entry-actions{margin-bottom:20px}.entry-actions a{text-decoration:none}.entry-actions li{display:inline}.entry-actions li:not(:last-child):after{content:"|"}.entry-meta{font-size:.95em;margin:0 0 20px;color:#666;overflow-wrap:break-word}.entry-website img{vertical-align:top}.entry-website a{color:#666;vertical-align:top;text-decoration:none}.entry-website a:hover,.entry-website a:focus{text-decoration:underline}.entry-date{font-size:.65em;font-style:italic;color:#555}.entry-content{padding-top:15px;font-size:1.2em;font-weight:300;font-family:Georgia,times new roman,Times,serif;color:#555;line-height:1.4em;overflow-wrap:break-word}.entry-content h1,h2,h3,h4,h5,h6{margin-top:15px;margin-bottom:10px}.entry-content iframe,.entry-content video,.entry-content img{max-width:100%}.entry-content figure{margin-top:15px;margin-bottom:15px}.entry-content figure img{border:1px solid #000}.entry-content figcaption{font-size:.75em;text-transform:uppercase;color:#777}.entry-content p{margin-top:10px;margin-bottom:15px}.entry-content a{overflow-wrap:break-word}.entry-content a:visited{color:purple}.entry-content dt{font-weight:500;margin-top:15px;color:#555}.entry-content dd{margin-left:15px;margin-top:5px;padding-left:20px;border-left:3px solid #ddd;color:#777;font-weight:300;line-height:1.4em}.entry-content blockquote{border-left:4px solid #ddd;padding-left:25px;margin-left:20px;margin-top:20px;margin-bottom:20px;color:#888;line-height:1.4em;font-family:Georgia,serif}.entry-content blockquote+p{color:#555;font-style:italic;font-weight:200}.entry-content q{color:purple;font-family:Georgia,serif;font-style:italic}.entry-content q:before{content:"“"}.entry-content q:after{content:"”"}.entry-content pre{padding:5px;background:#f0f0f0;border:1px solid #ddd;overflow:scroll;overflow-wrap:initial}.entry-content table{table-layout:fixed;max-width:100%}.entry-content ul,.entry-content ol{margin-left:30px}.entry-content ul{list-style-type:square}.entry-enclosures h3{font-weight:500}.entry-enclosure{border:1px dotted #ddd;padding:5px;margin-top:10px;max-width:100%}.entry-enclosure-download{font-size:.85em;overflow-wrap:break-word}.enclosure-video video,.enclosure-image img{max-width:100%}.confirm{font-weight:500;color:#ed2d04}.confirm a{color:#ed2d04}.loading{font-style:italic}.bookmarklet{border:1px dashed #ccc;border-radius:5px;padding:15px;margin:15px;text-align:center}.bookmarklet a{font-weight:600;text-decoration:none;font-size:1.2em}`,
+ "common": `*{margin:0;padding:0;box-sizing:border-box}body{font-family:helvetica neue,Helvetica,Arial,sans-serif;text-rendering:optimizeLegibility}main{padding-left:5px;padding-right:5px;margin-bottom:30px}a{color:#36c}a:focus{outline:0;color:red;text-decoration:none;border:1px dotted #aaa}a:hover{color:#333;text-decoration:none}.header{margin-top:10px;margin-bottom:20px}.header nav ul{display:none}.header li{cursor:pointer;padding-left:10px;line-height:2.1em;font-size:1.2em;border-bottom:1px dotted #ddd}.header li:hover a{color:#888}.header a{font-size:.9em;color:#444;text-decoration:none;border:0}.header .active a{font-weight:600}.header a:hover,.header a:focus{color:#888}.page-header{margin-bottom:25px}.page-header h1{font-weight:500;border-bottom:1px dotted #ddd}.page-header ul{margin-left:25px}.page-header li{list-style-type:circle;line-height:1.8em}.logo{cursor:pointer;text-align:center}.logo a{color:#000;letter-spacing:1px}.logo a:hover{color:#396}.logo a span{color:#396}.logo a:hover span{color:#000}@media(min-width:600px){body{margin:auto;max-width:750px}.logo{text-align:left;float:left;margin-right:15px}.header nav ul{display:block}.header li{display:inline;padding:0;padding-right:15px;line-height:normal;border:0;font-size:1em}.page-header ul{margin-left:0}.page-header li{display:inline;padding-right:15px}}table{width:100%;border-collapse:collapse}table,th,td{border:1px solid #ddd}th,td{padding:5px;text-align:left}td{vertical-align:top}th{background:#fcfcfc}tr:hover{background-color:#f9f9f9}.column-40{width:40%}.column-25{width:25%}.column-20{width:20%}fieldset{border:1px solid #ddd;padding:8px}legend{font-weight:500;padding-left:3px;padding-right:3px}label{cursor:pointer;display:block}.radio-group{line-height:1.9em}div.radio-group label{display:inline-block}select{margin-bottom:15px}input[type=url],input[type=password],input[type=text]{border:1px solid #ccc;padding:3px;line-height:20px;width:250px;font-size:99%;margin-bottom:10px;margin-top:5px;-webkit-appearance:none}input[type=url]:focus,input[type=password]:focus,input[type=text]:focus{color:#000;border-color:rgba(82,168,236,.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,.6)}input[type=checkbox]{margin-bottom:15px}::-moz-placeholder,::-ms-input-placeholder,::-webkit-input-placeholder{color:#ddd;padding-top:2px}.form-help{font-size:.9em;color:brown;margin-bottom:15px}.form-section{border-left:2px dotted #ddd;padding-left:20px;margin-left:10px}a.button{text-decoration:none}.button{display:inline-block;-webkit-appearance:none;-moz-appearance:none;font-size:1.1em;cursor:pointer;padding:3px 10px;border:1px solid;border-radius:unset}.button-primary{border-color:#3079ed;background:#4d90fe;color:#fff}.button-primary:hover,.button-primary:focus{border-color:#2f5bb7;background:#357ae8}.button-danger{border-color:#b0281a;background:#d14836;color:#fff}.button-danger:hover,.button-danger:focus{color:#fff;background:#c53727}.button:disabled{color:#ccc;background:#f7f7f7;border-color:#ccc}.buttons{margin-top:10px;margin-bottom:20px}.alert{padding:8px 35px 8px 14px;margin-bottom:20px;color:#c09853;background-color:#fcf8e3;border:1px solid #fbeed5;border-radius:4px;overflow:auto}.alert h3{margin-top:0;margin-bottom:15px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-error a{color:#b94a48}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.panel{color:#333;background-color:#fcfcfc;border:1px solid #ddd;border-radius:5px;padding:10px;margin-bottom:15px}.panel h3{font-weight:500;margin-top:0;margin-bottom:20px}.panel ul{margin-left:30px}#modal-left{position:fixed;top:0;left:0;bottom:0;width:350px;overflow:auto;background:#f0f0f0;box-shadow:2px 0 5px 0 #ccc;padding:5px;padding-top:30px}#modal-left h3{font-weight:400}.btn-close-modal{position:absolute;top:0;right:0;font-size:1.7em;color:#ccc;padding:0 .2em;margin:10px;text-decoration:none}.btn-close-modal:hover{color:#999}.keyboard-shortcuts li{margin-left:25px;list-style-type:square;color:#333;font-size:.95em;line-height:1.45em}.keyboard-shortcuts p{line-height:1.9em}.login-form{margin:50px auto 0;max-width:280px}.unread-counter-wrapper{font-size:.9em;font-weight:300;color:#666}.category{font-size:.75em;background-color:#fffcd7;border:1px solid #d5d458;border-radius:5px;margin-left:.25em;padding:1px .4em;white-space:nowrap}.category a{color:#555;text-decoration:none}.category a:hover,.category a:focus{color:#000}.pagination{font-size:1.1em;display:flex;align-items:center;padding-top:8px}.pagination-bottom{border-top:1px dotted #ddd;margin-bottom:15px;margin-top:50px}.pagination>div{flex:1}.pagination-next{text-align:right}.pagination-prev:before{content:"« "}.pagination-next:after{content:" »"}.pagination a{color:#333}.pagination a:hover,.pagination a:focus{text-decoration:none}.item{border:1px dotted #ddd;margin-bottom:20px;padding:5px;overflow:hidden}.item.current-item{border:3px solid #bce;padding:3px}.item-title a{text-decoration:none;font-weight:600}.item-status-read .item-title a{color:#777}.item-meta{color:#777;font-size:.8em}.item-meta a{color:#777;text-decoration:none}.item-meta a:hover,.item-meta a:focus{color:#333}.item-meta ul{margin-top:5px}.item-meta li{display:inline}.item-meta li:after{content:"|";color:#aaa}.item-meta li:last-child:after{content:""}.items{overflow-x:hidden}.hide-read-items .item-status-read{display:none}article.feed-parsing-error{background-color:#fcf8e3;border-color:#aaa}.parsing-error{font-size:.85em;margin-top:2px;color:#333}.parsing-error-count{cursor:pointer}.entry header{padding-bottom:5px;border-bottom:1px dotted #ddd}.entry header h1{font-size:2em;line-height:1.25em;margin:30px 0}.entry header h1 a{text-decoration:none;color:#333}.entry header h1 a:hover,.entry header h1 a:focus{color:#666}.entry-actions{margin-bottom:20px}.entry-actions a{text-decoration:none}.entry-actions li{display:inline}.entry-actions li:not(:last-child):after{content:"|"}.entry-meta{font-size:.95em;margin:0 0 20px;color:#666;overflow-wrap:break-word}.entry-website img{vertical-align:top}.entry-website a{color:#666;vertical-align:top;text-decoration:none}.entry-website a:hover,.entry-website a:focus{text-decoration:underline}.entry-date{font-size:.65em;font-style:italic;color:#555}.entry-content{padding-top:15px;font-size:1.2em;font-weight:300;font-family:Georgia,times new roman,Times,serif;color:#555;line-height:1.4em;overflow-wrap:break-word}.entry-content h1,h2,h3,h4,h5,h6{margin-top:15px;margin-bottom:10px}.entry-content iframe,.entry-content video,.entry-content img{max-width:100%}.entry-content figure{margin-top:15px;margin-bottom:15px}.entry-content figure img{border:1px solid #000}.entry-content figcaption{font-size:.75em;text-transform:uppercase;color:#777}.entry-content p{margin-top:10px;margin-bottom:15px}.entry-content a{overflow-wrap:break-word}.entry-content a:visited{color:purple}.entry-content dt{font-weight:500;margin-top:15px;color:#555}.entry-content dd{margin-left:15px;margin-top:5px;padding-left:20px;border-left:3px solid #ddd;color:#777;font-weight:300;line-height:1.4em}.entry-content blockquote{border-left:4px solid #ddd;padding-left:25px;margin-left:20px;margin-top:20px;margin-bottom:20px;color:#888;line-height:1.4em;font-family:Georgia,serif}.entry-content blockquote+p{color:#555;font-style:italic;font-weight:200}.entry-content q{color:purple;font-family:Georgia,serif;font-style:italic}.entry-content q:before{content:"“"}.entry-content q:after{content:"”"}.entry-content pre{padding:5px;background:#f0f0f0;border:1px solid #ddd;overflow:scroll;overflow-wrap:initial}.entry-content table{table-layout:fixed;max-width:100%}.entry-content ul,.entry-content ol{margin-left:30px}.entry-content ul{list-style-type:square}.entry-enclosures h3{font-weight:500}.entry-enclosure{border:1px dotted #ddd;padding:5px;margin-top:10px;max-width:100%}.entry-enclosure-download{font-size:.85em;overflow-wrap:break-word}.enclosure-video video,.enclosure-image img{max-width:100%}.confirm{font-weight:500;color:#ed2d04}.confirm a{color:#ed2d04}.loading{font-style:italic}.bookmarklet{border:1px dashed #ccc;border-radius:5px;padding:15px;margin:15px;text-align:center}.bookmarklet a{font-weight:600;text-decoration:none;font-size:1.2em}`,
"sansserif": `body,.entry-content,.entry-content blockquote,.entry-content q{font-family:-apple-system,BlinkMacSystemFont,segoe ui,Roboto,helvetica neue,Arial,sans-serif,apple color emoji,segoe ui emoji,segoe ui symbol}.entry-content{font-size:1.17em;font-weight:400}`,
}
var StylesheetsChecksums = map[string]string{
"black": "15eb9481c7dabbb39280570f388efd8bfcb36c8669294d003528cecb67c05e60",
- "common": "fd2e0ec67275f775415373a03fdacb287be65a69a8d3c3d6490079589250d122",
+ "common": "73ffb8a6ea6703443c7c515c367473ab8371db69e2b2f87420ab569cb2dd8555",
"sansserif": "3d60fb97530e032f350ae14223924f38a369044b9a89c25f9506c00604f7189b",
}
diff --git a/ui/static/css/common.css b/ui/static/css/common.css
index 2cd6d3c..de0daa9 100644
--- a/ui/static/css/common.css
+++ b/ui/static/css/common.css
@@ -184,6 +184,17 @@ tr:hover {
}
/* Forms */
+fieldset {
+ border: 1px solid #ddd;
+ padding: 8px;
+}
+
+legend {
+ font-weight: 500;
+ padding-left: 3px;
+ padding-right: 3px;
+}
+
label {
cursor: pointer;
display: block;
diff --git a/ui/static/js.go b/ui/static/js.go
index 8595161..b9c61aa 100644
--- a/ui/static/js.go
+++ b/ui/static/js.go
@@ -1,5 +1,5 @@
// Code generated by go generate; DO NOT EDIT.
-// 2018-06-06 18:30:00.64689124 +0000 UTC m=+0.004975400
+// 2018-06-19 22:56:40.308801738 -0700 PDT m=+0.030613858
package static
diff --git a/ui/subscription_choose.go b/ui/subscription_choose.go
index be97441..ce5a773 100644
--- a/ui/subscription_choose.go
+++ b/ui/subscription_choose.go
@@ -47,7 +47,14 @@ func (c *Controller) ChooseSubscription(w http.ResponseWriter, r *http.Request)
return
}
- feed, err := c.feedHandler.CreateFeed(user.ID, subscriptionForm.CategoryID, subscriptionForm.URL, subscriptionForm.Crawler)
+ feed, err := c.feedHandler.CreateFeed(
+ user.ID,
+ subscriptionForm.CategoryID,
+ subscriptionForm.URL,
+ subscriptionForm.Crawler,
+ subscriptionForm.Username,
+ subscriptionForm.Password,
+ )
if err != nil {
view.Set("form", subscriptionForm)
view.Set("errorMessage", err)
diff --git a/ui/subscription_submit.go b/ui/subscription_submit.go
index f4767a2..37f1016 100644
--- a/ui/subscription_submit.go
+++ b/ui/subscription_submit.go
@@ -49,7 +49,11 @@ func (c *Controller) SubmitSubscription(w http.ResponseWriter, r *http.Request)
return
}
- subscriptions, err := subscription.FindSubscriptions(subscriptionForm.URL)
+ subscriptions, err := subscription.FindSubscriptions(
+ subscriptionForm.URL,
+ subscriptionForm.Username,
+ subscriptionForm.Password,
+ )
if err != nil {
logger.Error("[Controller:SubmitSubscription] %v", err)
v.Set("form", subscriptionForm)
@@ -67,7 +71,14 @@ func (c *Controller) SubmitSubscription(w http.ResponseWriter, r *http.Request)
v.Set("errorMessage", "Unable to find any subscription.")
html.OK(w, v.Render("add_subscription"))
case n == 1:
- feed, err := c.feedHandler.CreateFeed(user.ID, subscriptionForm.CategoryID, subscriptions[0].URL, subscriptionForm.Crawler)
+ feed, err := c.feedHandler.CreateFeed(
+ user.ID,
+ subscriptionForm.CategoryID,
+ subscriptions[0].URL,
+ subscriptionForm.Crawler,
+ subscriptionForm.Username,
+ subscriptionForm.Password,
+ )
if err != nil {
v.Set("form", subscriptionForm)
v.Set("errorMessage", err)
@@ -79,7 +90,7 @@ func (c *Controller) SubmitSubscription(w http.ResponseWriter, r *http.Request)
case n > 1:
v := view.New(c.tpl, ctx, sess)
v.Set("subscriptions", subscriptions)
- v.Set("categoryID", subscriptionForm.CategoryID)
+ v.Set("form", subscriptionForm)
v.Set("menu", "feeds")
v.Set("user", user)
v.Set("countUnread", c.store.CountUnreadEntries(user.ID))