mirror of
https://github.com/miniflux/v2.git
synced 2024-10-01 06:41:15 +02:00
Add Wallabag integration
This commit is contained in:
parent
ce75748cf2
commit
b153fa8b3c
@ -5,10 +5,14 @@
|
|||||||
package http
|
package http
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/miniflux/miniflux/helper"
|
"github.com/miniflux/miniflux/helper"
|
||||||
@ -21,20 +25,59 @@ const requestTimeout = 300
|
|||||||
|
|
||||||
// Client is a HTTP Client :)
|
// Client is a HTTP Client :)
|
||||||
type Client struct {
|
type Client struct {
|
||||||
url string
|
url string
|
||||||
etagHeader string
|
etagHeader string
|
||||||
lastModifiedHeader string
|
lastModifiedHeader string
|
||||||
username string
|
authorizationHeader string
|
||||||
password string
|
username string
|
||||||
Insecure bool
|
password string
|
||||||
|
Insecure bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get execute a GET HTTP request.
|
// Get execute a GET HTTP request.
|
||||||
func (c *Client) Get() (*Response, error) {
|
func (c *Client) Get() (*Response, error) {
|
||||||
defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[HttpClient:Get] url=%s", c.url))
|
defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[HttpClient:Get] url=%s", c.url))
|
||||||
|
|
||||||
|
request, err := c.buildRequest(http.MethodGet, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.executeRequest(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostForm execute a POST HTTP request with form values.
|
||||||
|
func (c *Client) PostForm(values url.Values) (*Response, error) {
|
||||||
|
request, err := c.buildRequest(http.MethodPost, strings.NewReader(values.Encode()))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
request.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
return c.executeRequest(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostJSON execute a POST HTTP request with JSON payload.
|
||||||
|
func (c *Client) PostJSON(data interface{}) (*Response, error) {
|
||||||
|
b, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
request, err := c.buildRequest(http.MethodPost, bytes.NewReader(b))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
request.Header.Add("Content-Type", "application/json")
|
||||||
|
return c.executeRequest(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) executeRequest(request *http.Request) (*Response, error) {
|
||||||
|
defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[HttpClient] url=%s", c.url))
|
||||||
|
|
||||||
client := c.buildClient()
|
client := c.buildClient()
|
||||||
resp, err := client.Do(c.buildRequest())
|
resp, err := client.Do(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -48,7 +91,8 @@ func (c *Client) Get() (*Response, error) {
|
|||||||
ContentType: resp.Header.Get("Content-Type"),
|
ContentType: resp.Header.Get("Content-Type"),
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Debug("[HttpClient:Get] OriginalURL=%s, StatusCode=%d, ETag=%s, LastModified=%s, EffectiveURL=%s",
|
logger.Debug("[HttpClient:%s] OriginalURL=%s, StatusCode=%d, ETag=%s, LastModified=%s, EffectiveURL=%s",
|
||||||
|
request.Method,
|
||||||
c.url,
|
c.url,
|
||||||
response.StatusCode,
|
response.StatusCode,
|
||||||
response.ETag,
|
response.ETag,
|
||||||
@ -59,19 +103,18 @@ func (c *Client) Get() (*Response, error) {
|
|||||||
return response, err
|
return response, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) buildRequest() *http.Request {
|
func (c *Client) buildRequest(method string, body io.Reader) (*http.Request, error) {
|
||||||
link, _ := url.Parse(c.url)
|
request, err := http.NewRequest(method, c.url, body)
|
||||||
request := &http.Request{
|
if err != nil {
|
||||||
URL: link,
|
return nil, err
|
||||||
Method: http.MethodGet,
|
|
||||||
Header: c.buildHeaders(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.username != "" && c.password != "" {
|
if c.username != "" && c.password != "" {
|
||||||
request.SetBasicAuth(c.username, c.password)
|
request.SetBasicAuth(c.username, c.password)
|
||||||
}
|
}
|
||||||
|
|
||||||
return request
|
request.Header = c.buildHeaders()
|
||||||
|
return request, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) buildClient() http.Client {
|
func (c *Client) buildClient() http.Client {
|
||||||
@ -88,7 +131,7 @@ func (c *Client) buildClient() http.Client {
|
|||||||
func (c *Client) buildHeaders() http.Header {
|
func (c *Client) buildHeaders() http.Header {
|
||||||
headers := make(http.Header)
|
headers := make(http.Header)
|
||||||
headers.Add("User-Agent", userAgent)
|
headers.Add("User-Agent", userAgent)
|
||||||
headers.Add("Accept", "text/html,application/xhtml+xml,application/xml,application/json")
|
headers.Add("Accept", "text/html,application/xhtml+xml,application/xml,application/json,image/*")
|
||||||
|
|
||||||
if c.etagHeader != "" {
|
if c.etagHeader != "" {
|
||||||
headers.Add("If-None-Match", c.etagHeader)
|
headers.Add("If-None-Match", c.etagHeader)
|
||||||
@ -98,6 +141,10 @@ func (c *Client) buildHeaders() http.Header {
|
|||||||
headers.Add("If-Modified-Since", c.lastModifiedHeader)
|
headers.Add("If-Modified-Since", c.lastModifiedHeader)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.authorizationHeader != "" {
|
||||||
|
headers.Add("Authorization", c.authorizationHeader)
|
||||||
|
}
|
||||||
|
|
||||||
return headers
|
return headers
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,11 +153,16 @@ func NewClient(url string) *Client {
|
|||||||
return &Client{url: url, Insecure: false}
|
return &Client{url: url, Insecure: false}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClientWithCredentials returns a new HTTP client that require authentication.
|
// NewClientWithCredentials returns a new HTTP client that requires authentication.
|
||||||
func NewClientWithCredentials(url, username, password string) *Client {
|
func NewClientWithCredentials(url, username, password string) *Client {
|
||||||
return &Client{url: url, Insecure: false, username: username, password: password}
|
return &Client{url: url, Insecure: false, username: username, password: password}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewClientWithAuthorization returns a new client with a custom authorization header.
|
||||||
|
func NewClientWithAuthorization(url, authorization string) *Client {
|
||||||
|
return &Client{url: url, Insecure: false, authorizationHeader: authorization}
|
||||||
|
}
|
||||||
|
|
||||||
// NewClientWithCacheHeaders returns a new HTTP client that send cache headers.
|
// NewClientWithCacheHeaders returns a new HTTP client that send cache headers.
|
||||||
func NewClientWithCacheHeaders(url, etagHeader, lastModifiedHeader string) *Client {
|
func NewClientWithCacheHeaders(url, etagHeader, lastModifiedHeader string) *Client {
|
||||||
return &Client{url: url, etagHeader: etagHeader, lastModifiedHeader: lastModifiedHeader, Insecure: false}
|
return &Client{url: url, etagHeader: etagHeader, lastModifiedHeader: lastModifiedHeader, Insecure: false}
|
||||||
|
@ -27,7 +27,7 @@ func (c *Client) AddURL(link, title string) error {
|
|||||||
client := http.NewClientWithCredentials(apiURL, c.username, c.password)
|
client := http.NewClientWithCredentials(apiURL, c.username, c.password)
|
||||||
response, err := client.Get()
|
response, err := client.Get()
|
||||||
if response.HasServerFailure() {
|
if response.HasServerFailure() {
|
||||||
return fmt.Errorf("unable to send bookmark to instapaper, status=%d", response.StatusCode)
|
return fmt.Errorf("instapaper: unable to send url, status=%d", response.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
|
@ -7,6 +7,7 @@ package integration
|
|||||||
import (
|
import (
|
||||||
"github.com/miniflux/miniflux/integration/instapaper"
|
"github.com/miniflux/miniflux/integration/instapaper"
|
||||||
"github.com/miniflux/miniflux/integration/pinboard"
|
"github.com/miniflux/miniflux/integration/pinboard"
|
||||||
|
"github.com/miniflux/miniflux/integration/wallabag"
|
||||||
"github.com/miniflux/miniflux/logger"
|
"github.com/miniflux/miniflux/logger"
|
||||||
"github.com/miniflux/miniflux/model"
|
"github.com/miniflux/miniflux/model"
|
||||||
)
|
)
|
||||||
@ -15,17 +16,36 @@ import (
|
|||||||
func SendEntry(entry *model.Entry, integration *model.Integration) {
|
func SendEntry(entry *model.Entry, integration *model.Integration) {
|
||||||
if integration.PinboardEnabled {
|
if integration.PinboardEnabled {
|
||||||
client := pinboard.NewClient(integration.PinboardToken)
|
client := pinboard.NewClient(integration.PinboardToken)
|
||||||
err := client.AddBookmark(entry.URL, entry.Title, integration.PinboardTags, integration.PinboardMarkAsUnread)
|
err := client.AddBookmark(
|
||||||
|
entry.URL,
|
||||||
|
entry.Title,
|
||||||
|
integration.PinboardTags,
|
||||||
|
integration.PinboardMarkAsUnread,
|
||||||
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("[Pinboard] %v", err)
|
logger.Error("[Integration] %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if integration.InstapaperEnabled {
|
if integration.InstapaperEnabled {
|
||||||
client := instapaper.NewClient(integration.InstapaperUsername, integration.InstapaperPassword)
|
client := instapaper.NewClient(integration.InstapaperUsername, integration.InstapaperPassword)
|
||||||
err := client.AddURL(entry.URL, entry.Title)
|
if err := client.AddURL(entry.URL, entry.Title); err != nil {
|
||||||
if err != nil {
|
logger.Error("[Integration] %v", err)
|
||||||
logger.Error("[Instapaper] %v", err)
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if integration.WallabagEnabled {
|
||||||
|
client := wallabag.NewClient(
|
||||||
|
integration.WallabagURL,
|
||||||
|
integration.WallabagClientID,
|
||||||
|
integration.WallabagClientSecret,
|
||||||
|
integration.WallabagUsername,
|
||||||
|
integration.WallabagPassword,
|
||||||
|
)
|
||||||
|
|
||||||
|
if err := client.AddEntry(entry.URL, entry.Title); err != nil {
|
||||||
|
logger.Error("[Integration] %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ func (c *Client) AddBookmark(link, title, tags string, markAsUnread bool) error
|
|||||||
client := http.NewClient("https://api.pinboard.in/v1/posts/add?" + values.Encode())
|
client := http.NewClient("https://api.pinboard.in/v1/posts/add?" + values.Encode())
|
||||||
response, err := client.Get()
|
response, err := client.Get()
|
||||||
if response.HasServerFailure() {
|
if response.HasServerFailure() {
|
||||||
return fmt.Errorf("unable to send bookmark to pinboard, status=%d", response.StatusCode)
|
return fmt.Errorf("pinboard: unable to send bookmark, status=%d", response.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
|
116
integration/wallabag/wallabag.go
Normal file
116
integration/wallabag/wallabag.go
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
// Copyright 2017 Frédéric Guillot. All rights reserved.
|
||||||
|
// Use of this source code is governed by the Apache 2.0
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package wallabag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/miniflux/miniflux/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Client represents a Wallabag client.
|
||||||
|
type Client struct {
|
||||||
|
baseURL string
|
||||||
|
clientID string
|
||||||
|
clientSecret string
|
||||||
|
username string
|
||||||
|
password string
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddEntry sends a link to Wallabag.
|
||||||
|
func (c *Client) AddEntry(link, title string) error {
|
||||||
|
accessToken, err := c.getAccessToken()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.createEntry(accessToken, link, title)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) createEntry(accessToken, link, title string) error {
|
||||||
|
endpoint, err := getAPIEndpoint(c.baseURL, "/api/entries.json")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("wallbag: unable to get entries endpoint: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
client := http.NewClientWithAuthorization(endpoint, "Bearer "+accessToken)
|
||||||
|
response, err := client.PostJSON(map[string]string{"url": link, "title": title})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("wallabag: unable to post entry: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if response.HasServerFailure() {
|
||||||
|
return fmt.Errorf("wallabag: request failed, status=%d", response.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) getAccessToken() (string, error) {
|
||||||
|
values := url.Values{}
|
||||||
|
values.Add("grant_type", "password")
|
||||||
|
values.Add("client_id", c.clientID)
|
||||||
|
values.Add("client_secret", c.clientSecret)
|
||||||
|
values.Add("username", c.username)
|
||||||
|
values.Add("password", c.password)
|
||||||
|
|
||||||
|
endpoint, err := getAPIEndpoint(c.baseURL, "/oauth/v2/token")
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("wallbag: unable to get token endpoint: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
client := http.NewClient(endpoint)
|
||||||
|
response, err := client.PostForm(values)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("wallabag: unable to get access token: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if response.HasServerFailure() {
|
||||||
|
return "", fmt.Errorf("wallabag: request failed, status=%d", response.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := decodeTokenResponse(response.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return token.AccessToken, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClient returns a new Wallabag client.
|
||||||
|
func NewClient(baseURL, clientID, clientSecret, username, password string) *Client {
|
||||||
|
return &Client{baseURL, clientID, clientSecret, username, password}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAPIEndpoint(baseURL, path string) (string, error) {
|
||||||
|
u, err := url.Parse(baseURL)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("wallabag: invalid API endpoint: %v", err)
|
||||||
|
}
|
||||||
|
u.Path = path
|
||||||
|
return u.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type tokenResponse struct {
|
||||||
|
AccessToken string `json:"access_token"`
|
||||||
|
Expires int `json:"expires_in"`
|
||||||
|
RefreshToken string `json:"refresh_token"`
|
||||||
|
Scope string `json:"scope"`
|
||||||
|
TokenType string `json:"token_type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeTokenResponse(body io.Reader) (*tokenResponse, error) {
|
||||||
|
var token tokenResponse
|
||||||
|
|
||||||
|
decoder := json.NewDecoder(body)
|
||||||
|
if err := decoder.Decode(&token); err != nil {
|
||||||
|
return nil, fmt.Errorf("wallabag: unable to decode token response: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &token, nil
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
// Code generated by go generate; DO NOT EDIT.
|
// Code generated by go generate; DO NOT EDIT.
|
||||||
// 2017-12-16 17:48:32.323083386 -0800 PST m=+0.056720065
|
// 2017-12-18 18:49:32.159555255 -0800 PST m=+0.041213049
|
||||||
|
|
||||||
package locale
|
package locale
|
||||||
|
|
||||||
@ -171,12 +171,18 @@ var translations = map[string]string{
|
|||||||
"Scraper Rules": "Règles pour récupérer le contenu original",
|
"Scraper Rules": "Règles pour récupérer le contenu original",
|
||||||
"Rewrite Rules": "Règles de réécriture",
|
"Rewrite Rules": "Règles de réécriture",
|
||||||
"Preferences saved!": "Préférences sauvegardées !",
|
"Preferences saved!": "Préférences sauvegardées !",
|
||||||
"Your external account is now linked !": "Votre compte externe est maintenant associé !"
|
"Your external account is now linked !": "Votre compte externe est maintenant associé !",
|
||||||
|
"Save articles to Wallabag": "Sauvegarder les articles vers Wallabag",
|
||||||
|
"Wallabag API Endpoint": "URL de l'API de Wallabag",
|
||||||
|
"Wallabag Client ID": "Identifiant du client Wallabag",
|
||||||
|
"Wallabag Client Secret": "Clé secrète du client Wallabag",
|
||||||
|
"Wallabag Username": "Nom d'utilisateur de Wallabag",
|
||||||
|
"Wallabag Password": "Mot de passe de Wallabag"
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
|
|
||||||
var translationsChecksums = map[string]string{
|
var translationsChecksums = map[string]string{
|
||||||
"en_US": "6fe95384260941e8a5a3c695a655a932e0a8a6a572c1e45cb2b1ae8baa01b897",
|
"en_US": "6fe95384260941e8a5a3c695a655a932e0a8a6a572c1e45cb2b1ae8baa01b897",
|
||||||
"fr_FR": "f52a6503ee61d1103adb280c242d438a89936b34d147d29c2502cec8b2cc9ff9",
|
"fr_FR": "3a71dbf4fcdb488acdaf43530e521a0c17a28ef637fbd60b204e468afb0dbe09",
|
||||||
}
|
}
|
||||||
|
@ -155,5 +155,11 @@
|
|||||||
"Scraper Rules": "Règles pour récupérer le contenu original",
|
"Scraper Rules": "Règles pour récupérer le contenu original",
|
||||||
"Rewrite Rules": "Règles de réécriture",
|
"Rewrite Rules": "Règles de réécriture",
|
||||||
"Preferences saved!": "Préférences sauvegardées !",
|
"Preferences saved!": "Préférences sauvegardées !",
|
||||||
"Your external account is now linked !": "Votre compte externe est maintenant associé !"
|
"Your external account is now linked !": "Votre compte externe est maintenant associé !",
|
||||||
|
"Save articles to Wallabag": "Sauvegarder les articles vers Wallabag",
|
||||||
|
"Wallabag API Endpoint": "URL de l'API de Wallabag",
|
||||||
|
"Wallabag Client ID": "Identifiant du client Wallabag",
|
||||||
|
"Wallabag Client Secret": "Clé secrète du client Wallabag",
|
||||||
|
"Wallabag Username": "Nom d'utilisateur de Wallabag",
|
||||||
|
"Wallabag Password": "Mot de passe de Wallabag"
|
||||||
}
|
}
|
||||||
|
@ -18,4 +18,10 @@ type Integration struct {
|
|||||||
FeverUsername string
|
FeverUsername string
|
||||||
FeverPassword string
|
FeverPassword string
|
||||||
FeverToken string
|
FeverToken string
|
||||||
|
WallabagEnabled bool
|
||||||
|
WallabagURL string
|
||||||
|
WallabagClientID string
|
||||||
|
WallabagClientSecret string
|
||||||
|
WallabagUsername string
|
||||||
|
WallabagPassword string
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ func NewSessionScheduler(store *storage.Storage, frequency int) {
|
|||||||
for _ = range c {
|
for _ = range c {
|
||||||
nbSessions := store.CleanOldSessions()
|
nbSessions := store.CleanOldSessions()
|
||||||
nbUserSessions := store.CleanOldUserSessions()
|
nbUserSessions := store.CleanOldUserSessions()
|
||||||
logger.Debug("[SessionScheduler] cleaned %d sessions and %d user sessions", nbSessions, nbUserSessions)
|
logger.Info("[SessionScheduler] cleaned %d sessions and %d user sessions", nbSessions, nbUserSessions)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
@ -71,6 +71,28 @@
|
|||||||
<input type="password" name="instapaper_password" id="form-instapaper-password" value="{{ .form.InstapaperPassword }}">
|
<input type="password" name="instapaper_password" id="form-instapaper-password" value="{{ .form.InstapaperPassword }}">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<h3>Wallabag</h3>
|
||||||
|
<div class="form-section">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="wallabag_enabled" value="1" {{ if .form.WallabagEnabled }}checked{{ end }}> {{ t "Save articles to Wallabag" }}
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="form-wallabag-url">{{ t "Wallabag API Endpoint" }}</label>
|
||||||
|
<input type="url" name="wallabag_url" id="form-wallabag-url" value="{{ .form.WallabagURL }}" placeholder="http://v2.wallabag.org/">
|
||||||
|
|
||||||
|
<label for="form-wallabag-client-id">{{ t "Wallabag Client ID" }}</label>
|
||||||
|
<input type="text" name="wallabag_client_id" id="form-wallabag-client-id" value="{{ .form.WallabagClientID }}">
|
||||||
|
|
||||||
|
<label for="form-wallabag-client-secret">{{ t "Wallabag Client Secret" }}</label>
|
||||||
|
<input type="password" name="wallabag_client_secret" id="form-wallabag-client-secret" value="{{ .form.WallabagClientSecret }}">
|
||||||
|
|
||||||
|
<label for="form-wallabag-username">{{ t "Wallabag Username" }}</label>
|
||||||
|
<input type="text" name="wallabag_username" id="form-wallabag-username" value="{{ .form.WallabagUsername }}">
|
||||||
|
|
||||||
|
<label for="form-wallabag-password">{{ t "Wallabag Password" }}</label>
|
||||||
|
<input type="password" name="wallabag_password" id="form-wallabag-password" value="{{ .form.WallabagPassword }}">
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<button type="submit" class="button button-primary" data-label-loading="{{ t "Loading..." }}">{{ t "Update" }}</button>
|
<button type="submit" class="button button-primary" data-label-loading="{{ t "Loading..." }}">{{ t "Update" }}</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Code generated by go generate; DO NOT EDIT.
|
// Code generated by go generate; DO NOT EDIT.
|
||||||
// 2017-12-15 18:49:24.044316922 -0800 PST m=+0.016912794
|
// 2017-12-18 18:49:32.144679579 -0800 PST m=+0.026337373
|
||||||
|
|
||||||
package template
|
package template
|
||||||
|
|
||||||
@ -882,6 +882,28 @@ var templateViewsMap = map[string]string{
|
|||||||
<input type="password" name="instapaper_password" id="form-instapaper-password" value="{{ .form.InstapaperPassword }}">
|
<input type="password" name="instapaper_password" id="form-instapaper-password" value="{{ .form.InstapaperPassword }}">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<h3>Wallabag</h3>
|
||||||
|
<div class="form-section">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="wallabag_enabled" value="1" {{ if .form.WallabagEnabled }}checked{{ end }}> {{ t "Save articles to Wallabag" }}
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="form-wallabag-url">{{ t "Wallabag API Endpoint" }}</label>
|
||||||
|
<input type="url" name="wallabag_url" id="form-wallabag-url" value="{{ .form.WallabagURL }}" placeholder="http://v2.wallabag.org/">
|
||||||
|
|
||||||
|
<label for="form-wallabag-client-id">{{ t "Wallabag Client ID" }}</label>
|
||||||
|
<input type="text" name="wallabag_client_id" id="form-wallabag-client-id" value="{{ .form.WallabagClientID }}">
|
||||||
|
|
||||||
|
<label for="form-wallabag-client-secret">{{ t "Wallabag Client Secret" }}</label>
|
||||||
|
<input type="password" name="wallabag_client_secret" id="form-wallabag-client-secret" value="{{ .form.WallabagClientSecret }}">
|
||||||
|
|
||||||
|
<label for="form-wallabag-username">{{ t "Wallabag Username" }}</label>
|
||||||
|
<input type="text" name="wallabag_username" id="form-wallabag-username" value="{{ .form.WallabagUsername }}">
|
||||||
|
|
||||||
|
<label for="form-wallabag-password">{{ t "Wallabag Password" }}</label>
|
||||||
|
<input type="password" name="wallabag_password" id="form-wallabag-password" value="{{ .form.WallabagPassword }}">
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<button type="submit" class="button button-primary" data-label-loading="{{ t "Loading..." }}">{{ t "Update" }}</button>
|
<button type="submit" class="button button-primary" data-label-loading="{{ t "Loading..." }}">{{ t "Update" }}</button>
|
||||||
</div>
|
</div>
|
||||||
@ -1201,7 +1223,7 @@ var templateViewsMapChecksums = map[string]string{
|
|||||||
"feeds": "c22af39b42ba9ca69ea0914ca789303ec2c5b484abcd4eaa49016e365381257c",
|
"feeds": "c22af39b42ba9ca69ea0914ca789303ec2c5b484abcd4eaa49016e365381257c",
|
||||||
"history": "9a67599a5d8d67ef958e3f07da339b749f42892667547c9e60a54477e8d32a56",
|
"history": "9a67599a5d8d67ef958e3f07da339b749f42892667547c9e60a54477e8d32a56",
|
||||||
"import": "73b5112e20bfd232bf73334544186ea419505936bc237d481517a8622901878f",
|
"import": "73b5112e20bfd232bf73334544186ea419505936bc237d481517a8622901878f",
|
||||||
"integrations": "30249eefa4e2da62051447537ee5c4ed3dad377656fec3080e0e96c3c697c672",
|
"integrations": "3c14d7de904911aad7f3ebec6d1a20b50843287f58125c526e167f429f3d455d",
|
||||||
"login": "04f3ce79bfa5753f69e0d956c2a8999c0da549c7925634a3e8134975da0b0e0f",
|
"login": "04f3ce79bfa5753f69e0d956c2a8999c0da549c7925634a3e8134975da0b0e0f",
|
||||||
"sessions": "878dbe8f8ea783b44130c495814179519fa5c3aa2666ac87508f94d58dd008bf",
|
"sessions": "878dbe8f8ea783b44130c495814179519fa5c3aa2666ac87508f94d58dd008bf",
|
||||||
"settings": "ea2505b9d0a6d6bb594dba87a92079de19baa6d494f0651693a7685489fb7de9",
|
"settings": "ea2505b9d0a6d6bb594dba87a92079de19baa6d494f0651693a7685489fb7de9",
|
||||||
|
@ -40,6 +40,12 @@ func (c *Controller) ShowIntegrations(ctx *core.Context, request *core.Request,
|
|||||||
FeverEnabled: integration.FeverEnabled,
|
FeverEnabled: integration.FeverEnabled,
|
||||||
FeverUsername: integration.FeverUsername,
|
FeverUsername: integration.FeverUsername,
|
||||||
FeverPassword: integration.FeverPassword,
|
FeverPassword: integration.FeverPassword,
|
||||||
|
WallabagEnabled: integration.WallabagEnabled,
|
||||||
|
WallabagURL: integration.WallabagURL,
|
||||||
|
WallabagClientID: integration.WallabagClientID,
|
||||||
|
WallabagClientSecret: integration.WallabagClientSecret,
|
||||||
|
WallabagUsername: integration.WallabagUsername,
|
||||||
|
WallabagPassword: integration.WallabagPassword,
|
||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,12 @@ type IntegrationForm struct {
|
|||||||
FeverEnabled bool
|
FeverEnabled bool
|
||||||
FeverUsername string
|
FeverUsername string
|
||||||
FeverPassword string
|
FeverPassword string
|
||||||
|
WallabagEnabled bool
|
||||||
|
WallabagURL string
|
||||||
|
WallabagClientID string
|
||||||
|
WallabagClientSecret string
|
||||||
|
WallabagUsername string
|
||||||
|
WallabagPassword string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge copy form values to the model.
|
// Merge copy form values to the model.
|
||||||
@ -36,6 +42,12 @@ func (i IntegrationForm) Merge(integration *model.Integration) {
|
|||||||
integration.FeverEnabled = i.FeverEnabled
|
integration.FeverEnabled = i.FeverEnabled
|
||||||
integration.FeverUsername = i.FeverUsername
|
integration.FeverUsername = i.FeverUsername
|
||||||
integration.FeverPassword = i.FeverPassword
|
integration.FeverPassword = i.FeverPassword
|
||||||
|
integration.WallabagEnabled = i.WallabagEnabled
|
||||||
|
integration.WallabagURL = i.WallabagURL
|
||||||
|
integration.WallabagClientID = i.WallabagClientID
|
||||||
|
integration.WallabagClientSecret = i.WallabagClientSecret
|
||||||
|
integration.WallabagUsername = i.WallabagUsername
|
||||||
|
integration.WallabagPassword = i.WallabagPassword
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewIntegrationForm returns a new AuthForm.
|
// NewIntegrationForm returns a new AuthForm.
|
||||||
@ -51,5 +63,11 @@ func NewIntegrationForm(r *http.Request) *IntegrationForm {
|
|||||||
FeverEnabled: r.FormValue("fever_enabled") == "1",
|
FeverEnabled: r.FormValue("fever_enabled") == "1",
|
||||||
FeverUsername: r.FormValue("fever_username"),
|
FeverUsername: r.FormValue("fever_username"),
|
||||||
FeverPassword: r.FormValue("fever_password"),
|
FeverPassword: r.FormValue("fever_password"),
|
||||||
|
WallabagEnabled: r.FormValue("wallabag_enabled") == "1",
|
||||||
|
WallabagURL: r.FormValue("wallabag_url"),
|
||||||
|
WallabagClientID: r.FormValue("wallabag_client_id"),
|
||||||
|
WallabagClientSecret: r.FormValue("wallabag_client_secret"),
|
||||||
|
WallabagUsername: r.FormValue("wallabag_username"),
|
||||||
|
WallabagPassword: r.FormValue("wallabag_password"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
6
sql/schema_version_11.sql
Normal file
6
sql/schema_version_11.sql
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
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_client_id text default '';
|
||||||
|
alter table integrations add column wallabag_client_secret text default '';
|
||||||
|
alter table integrations add column wallabag_username text default '';
|
||||||
|
alter table integrations add column wallabag_password text default '';
|
@ -1,5 +1,5 @@
|
|||||||
// Code generated by go generate; DO NOT EDIT.
|
// Code generated by go generate; DO NOT EDIT.
|
||||||
// 2017-12-16 17:48:32.268871258 -0800 PST m=+0.002507937
|
// 2017-12-18 18:49:32.121198779 -0800 PST m=+0.002856573
|
||||||
|
|
||||||
package sql
|
package sql
|
||||||
|
|
||||||
@ -116,6 +116,12 @@ create table sessions (
|
|||||||
created_at timestamp with time zone not null default now(),
|
created_at timestamp with time zone not null default now(),
|
||||||
primary key(id)
|
primary key(id)
|
||||||
);`,
|
);`,
|
||||||
|
"schema_version_11": `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_client_id text default '';
|
||||||
|
alter table integrations add column wallabag_client_secret text default '';
|
||||||
|
alter table integrations add column wallabag_username text default '';
|
||||||
|
alter table integrations add column wallabag_password text default '';`,
|
||||||
"schema_version_2": `create extension if not exists hstore;
|
"schema_version_2": `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);
|
||||||
@ -157,6 +163,7 @@ alter table users add column entry_direction entry_sorting_direction default 'as
|
|||||||
var SqlMapChecksums = map[string]string{
|
var SqlMapChecksums = map[string]string{
|
||||||
"schema_version_1": "7be580fc8a93db5da54b2f6e87019803c33b0b0c28482c7af80cef873bdac4e2",
|
"schema_version_1": "7be580fc8a93db5da54b2f6e87019803c33b0b0c28482c7af80cef873bdac4e2",
|
||||||
"schema_version_10": "8faf15ddeff7c8cc305e66218face11ed92b97df2bdc2d0d7944d61441656795",
|
"schema_version_10": "8faf15ddeff7c8cc305e66218face11ed92b97df2bdc2d0d7944d61441656795",
|
||||||
|
"schema_version_11": "dc5bbc302e01e425b49c48ddcd8e29e3ab2bb8e73a6cd1858a6ba9fbec0b5243",
|
||||||
"schema_version_2": "e8e9ff32478df04fcddad10a34cba2e8bb1e67e7977b5bd6cdc4c31ec94282b4",
|
"schema_version_2": "e8e9ff32478df04fcddad10a34cba2e8bb1e67e7977b5bd6cdc4c31ec94282b4",
|
||||||
"schema_version_3": "a54745dbc1c51c000f74d4e5068f1e2f43e83309f023415b1749a47d5c1e0f12",
|
"schema_version_3": "a54745dbc1c51c000f74d4e5068f1e2f43e83309f023415b1749a47d5c1e0f12",
|
||||||
"schema_version_4": "216ea3a7d3e1704e40c797b5dc47456517c27dbb6ca98bf88812f4f63d74b5d9",
|
"schema_version_4": "216ea3a7d3e1704e40c797b5dc47456517c27dbb6ca98bf88812f4f63d74b5d9",
|
||||||
|
@ -47,7 +47,13 @@ func (s *Storage) Integration(userID int64) (*model.Integration, error) {
|
|||||||
fever_enabled,
|
fever_enabled,
|
||||||
fever_username,
|
fever_username,
|
||||||
fever_password,
|
fever_password,
|
||||||
fever_token
|
fever_token,
|
||||||
|
wallabag_enabled,
|
||||||
|
wallabag_url,
|
||||||
|
wallabag_client_id,
|
||||||
|
wallabag_client_secret,
|
||||||
|
wallabag_username,
|
||||||
|
wallabag_password
|
||||||
FROM integrations
|
FROM integrations
|
||||||
WHERE user_id=$1
|
WHERE user_id=$1
|
||||||
`
|
`
|
||||||
@ -65,6 +71,12 @@ func (s *Storage) Integration(userID int64) (*model.Integration, error) {
|
|||||||
&integration.FeverUsername,
|
&integration.FeverUsername,
|
||||||
&integration.FeverPassword,
|
&integration.FeverPassword,
|
||||||
&integration.FeverToken,
|
&integration.FeverToken,
|
||||||
|
&integration.WallabagEnabled,
|
||||||
|
&integration.WallabagURL,
|
||||||
|
&integration.WallabagClientID,
|
||||||
|
&integration.WallabagClientSecret,
|
||||||
|
&integration.WallabagUsername,
|
||||||
|
&integration.WallabagPassword,
|
||||||
)
|
)
|
||||||
switch {
|
switch {
|
||||||
case err == sql.ErrNoRows:
|
case err == sql.ErrNoRows:
|
||||||
@ -90,8 +102,14 @@ func (s *Storage) UpdateIntegration(integration *model.Integration) error {
|
|||||||
fever_enabled=$8,
|
fever_enabled=$8,
|
||||||
fever_username=$9,
|
fever_username=$9,
|
||||||
fever_password=$10,
|
fever_password=$10,
|
||||||
fever_token=$11
|
fever_token=$11,
|
||||||
WHERE user_id=$12
|
wallabag_enabled=$12,
|
||||||
|
wallabag_url=$13,
|
||||||
|
wallabag_client_id=$14,
|
||||||
|
wallabag_client_secret=$15,
|
||||||
|
wallabag_username=$16,
|
||||||
|
wallabag_password=$17
|
||||||
|
WHERE user_id=$18
|
||||||
`
|
`
|
||||||
_, err := s.db.Exec(
|
_, err := s.db.Exec(
|
||||||
query,
|
query,
|
||||||
@ -106,6 +124,12 @@ func (s *Storage) UpdateIntegration(integration *model.Integration) error {
|
|||||||
integration.FeverUsername,
|
integration.FeverUsername,
|
||||||
integration.FeverPassword,
|
integration.FeverPassword,
|
||||||
integration.FeverToken,
|
integration.FeverToken,
|
||||||
|
integration.WallabagEnabled,
|
||||||
|
integration.WallabagURL,
|
||||||
|
integration.WallabagClientID,
|
||||||
|
integration.WallabagClientSecret,
|
||||||
|
integration.WallabagUsername,
|
||||||
|
integration.WallabagPassword,
|
||||||
integration.UserID,
|
integration.UserID,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ import (
|
|||||||
"github.com/miniflux/miniflux/sql"
|
"github.com/miniflux/miniflux/sql"
|
||||||
)
|
)
|
||||||
|
|
||||||
const schemaVersion = 10
|
const schemaVersion = 11
|
||||||
|
|
||||||
// Migrate run database migrations.
|
// Migrate run database migrations.
|
||||||
func (s *Storage) Migrate() {
|
func (s *Storage) Migrate() {
|
||||||
|
Loading…
Reference in New Issue
Block a user