Frontend: Add upgrade page and update about page

Signed-off-by: Michael Mayer <michael@photoprism.app>
This commit is contained in:
Michael Mayer 2022-11-27 18:00:55 +01:00
parent 0014e104fe
commit 53232b53c0
16 changed files with 312 additions and 112 deletions

View file

@ -2467,9 +2467,9 @@
"integrity": "sha512-Ewzq5Yhimg7pSztDV+RH1UDKBzmtqieXQlpTVm2AwraoRL/Rks96mvd8Vgi7Lj+h+TH8dv7mXD3FRZR3TUvbSg=="
},
"node_modules/@vvo/tzdb": {
"version": "6.76.0",
"resolved": "https://registry.npmjs.org/@vvo/tzdb/-/tzdb-6.76.0.tgz",
"integrity": "sha512-hDVkAaqDA5ti5izUiPFk7tYWu12D3MyM7BgCkJb++KSUpJbhMiEI+um2PhmWvMhXt5Fwz0OAIGpV5Xtfv63HVw=="
"version": "6.77.0",
"resolved": "https://registry.npmjs.org/@vvo/tzdb/-/tzdb-6.77.0.tgz",
"integrity": "sha512-t7aN3GAznzt8fQ5enJiM3C7HKPEDBoqKExp2W7nYu2AgS0J9FfMk6rwWhL2jjTe0+27REmO9C+TL3XM2evileQ=="
},
"node_modules/@webassemblyjs/ast": {
"version": "1.11.1",
@ -8355,9 +8355,9 @@
}
},
"node_modules/minipass": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.4.tgz",
"integrity": "sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw==",
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
"integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
"dependencies": {
"yallist": "^4.0.0"
},

View file

@ -34,12 +34,13 @@ import People from "page/people.vue";
import Library from "page/library.vue";
import Settings from "page/settings.vue";
import Login from "page/login.vue";
import Connect from "page/connect.vue";
import Discover from "page/discover.vue";
import About from "page/about/about.vue";
import Feedback from "page/about/feedback.vue";
import License from "page/about/license.vue";
import Help from "page/help.vue";
import Upgrade from "page/upgrade.vue";
import Connect from "page/connect.vue";
import { $gettext } from "common/vm";
import { config, session } from "./session";
@ -91,6 +92,16 @@ export default [
}
},
},
{
name: "upgrade",
path: "/upgrade",
component: Upgrade,
meta: {
title: siteTitle,
auth: true,
admin: true,
},
},
{
name: "connect",
path: "/connect/:name/:token",

View file

@ -471,7 +471,7 @@
</v-list-tile-content>
</v-list-tile>
<v-list-tile v-show="!isPublic && isAdmin" :to="{ name: 'feedback' }" :exact="true" class="nav-feedback"
<v-list-tile v-show="!isPublic && isAdmin && isSponsor" :to="{ name: 'feedback' }" :exact="true" class="nav-feedback"
@click.stop="">
<v-list-tile-content>
<v-list-tile-title :class="`menu-item ${rtl ? '--rtl' : ''}`">
@ -502,6 +502,17 @@
</v-list-tile-content>
</v-list-tile>
<v-list-tile v-show="isAdmin && !isPublic && !isDemo && !isSponsor" :to="{ name: 'upgrade' }" class="nav-upgrade" @click.stop="">
<v-list-tile-action :title="$gettext('Upgrade')">
<v-icon>diamond</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>
<translate key="Upgrade">Upgrade</translate>
</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</v-list>
<v-list class="p-user-box">
@ -622,21 +633,16 @@
<translate>Logs</translate>
</router-link>
</div>
<!-- div v-if="auth && $config.feature('account') && !routeName('settings')" class="menu-action nav-account">
<router-link :to="{ name: 'settings_account' }">
<v-icon>person</v-icon>
<translate>Account</translate>
<div v-if="!isPublic && !isSponsor && isAdmin" class="menu-action nav-membership">
<router-link :to="{ name: 'upgrade' }">
<v-icon>diamond</v-icon>
<translate>Upgrade</translate>
</router-link>
</div -->
</div>
<div class="menu-action nav-manual"><a href="https://link.photoprism.app/docs" target="_blank">
<v-icon>auto_stories</v-icon>
<translate>User Guide</translate>
</a></div>
<div v-if="!isSponsor && isAdmin" class="menu-action nav-membership"><a href="https://link.photoprism.app/membership"
target="_blank">
<v-icon>workspace_premium</v-icon>
<translate>Become a sponsor</translate>
</a></div>
<div v-if="config.legalUrl && isSponsor" class="menu-action nav-legal"><a :href="config.legalUrl"
target="_blank">
<v-icon>info</v-icon>

View file

@ -1,47 +1,49 @@
<template>
<v-dialog :value="show" lazy persistent max-width="500" class="modal-dialog sponsor-dialog" @keydown.esc="close">
<v-dialog :value="show" lazy persistent max-width="575" class="modal-dialog sponsor-dialog" @keydown.esc="close">
<v-card raised elevation="24">
<v-card-title primary-title class="pb-0">
<v-layout row wrap>
<v-flex xs9>
<v-card-title primary-title class="px-2 pb-0">
<v-layout row wrap class="px-2">
<v-flex xs10>
<h3 class="title mb-0">
<translate>Become a sponsor</translate>
<translate>Support Our Mission</translate>
</h3>
</v-flex>
<v-flex xs3 text-xs-right>
<v-icon color="secondary-dark">$vuetify.icons.sponsor</v-icon>
<v-flex xs2 text-xs-right>
<v-icon color="secondary-dark">diamond</v-icon>
</v-flex>
</v-layout>
</v-card-title>
<v-card-text>
<p class="body-1">
<translate>This currently is a sponsor feature to thank everyone who supports the development of this application.</translate>
<translate>We'll let you know how to enable it when you sign up on Patreon or GitHub Sponsors.</translate>
<v-card-text class="px-2">
<v-layout row wrap class="px-2">
<v-flex xs12 class="py-2">
<p class="body-2">
<translate>Your continued support helps us provide regular updates and remain independent, so we can fulfill our mission and protect your privacy.</translate>
</p>
<p class="body-1">
<translate>Your continued support helps us provide regular updates and services like world maps.</translate>
<translate>Being 100% self-funded and independent, we can promise you that we will never sell your data and that we will always be transparent about our software and services.</translate>
</p>
<p class="body-1">
<translate>Feel free to contact us at hello@photoprism.app if you have any questions.</translate>
</p>
</v-flex>
</v-layout>
</v-card-text>
<v-card-actions class="pt-0 px-3">
<v-card-actions class="pt-0 px-2">
<v-layout row wrap class="px-2">
<v-flex xs12 sm4 :text-xs-right="!rtl" :text-sm-left="!rtl" :text-xs-left="rtl" class="py-2">
<v-flex xs12 text-xs-right class="py-2">
<v-btn depressed color="secondary-light"
class="action-close compact"
@click.stop="close">
<translate>No thanks</translate>
</v-btn>
</v-flex>
<v-flex xs12 sm8 text-xs-right class="py-2">
<v-btn depressed color="primary-button" class="white--text action-close compact"
@click.stop="signIn">
<translate>I'm a sponsor</translate>
<v-btn v-if="isPublic || !isAdmin" href="https://link.photoprism.app/personal-editions"
target="_blank"
depressed color="primary-button" class="white--text action-about compact">
<translate>Learn more</translate>
</v-btn>
<v-btn depressed color="primary-button" class="white--text action-close compact"
@click.stop="signUp">
<translate>Sign Up</translate>
<v-btn v-else depressed color="primary-button" class="white--text action-upgrade compact"
@click.stop="upgrade">
<translate>Upgrade Now</translate>
</v-btn>
</v-flex>
</v-layout>
@ -57,6 +59,10 @@ export default {
},
data() {
return {
isPublic: this.$config.isPublic(),
isAdmin: this.$session.isAdmin(),
isDemo: this.$config.isDemo(),
isSponsor: this.$config.isSponsor(),
host: window.location.host,
rtl: this.$rtl,
};
@ -65,12 +71,8 @@ export default {
close() {
this.$emit('close');
},
signIn() {
window.open("https://photoprism.app/contact", "_blank");
this.$emit('close');
},
signUp() {
window.open("https://link.photoprism.app/membership", "_blank");
upgrade() {
this.$router.push({name: "upgrade"});
this.$emit('close');
},
},

File diff suppressed because one or more lines are too long

View file

@ -7,45 +7,47 @@
<v-spacer></v-spacer>
<v-btn icon href="https://photoprism.app/" target="_blank" class="action-info" :title="$gettext('About')">
<v-icon size="26">chat</v-icon>
<v-btn icon href="https://photoprism.app/" target="_blank" class="action-info" :title="$gettext('Learn more')">
<v-icon size="26">info</v-icon>
</v-btn>
</v-toolbar>
<v-container fluid class="px-4 pt-4 pb-1">
<p class="body-2 text-selectable">
<p class="subheading font-weight-bold text-selectable">
<translate>PhotoPrism® is an AI-Powered Photos App for the Decentralized Web.</translate>
<translate>It makes use of the latest technologies to tag and find pictures automatically without getting in your way.</translate>
<translate>You can run it at home, on a private server, or in the cloud.</translate>
</p>
<p class="body-1 text-selectable pb-1">
<span v-if="sponsor">
<p class="subheading text-selectable">
<translate>Your continued support helps us provide regular updates and remain independent, so we can fulfill our mission and protect your privacy.</translate>
</span>
<span v-else>
<translate>Sponsors get access to additional features, receive direct technical support via email, and can join our private chat room on matrix.org.</translate>
</span>
<translate>Being 100% self-funded and independent, we can promise you that we will never sell your data and that we will always be transparent about our software and services.</translate>
</p>
<div v-if="!sponsor">
<div v-if="isPublic">
<p class="text-xs-center my-4">
<v-btn
href="https://link.photoprism.app/membership"
href="https://link.photoprism.app/personal-editions"
target="_blank"
color="primary-button"
class="white--text px-3 py-2 action-sponsor"
round depressed small
class="white--text px-3 py-2 action-upgrade"
round depressed
>
<translate>Become a sponsor</translate>
<v-icon :left="rtl" :right="!rtl" size="16" class="ml-2" dark>star</v-icon>
<translate>Learn more</translate>
<v-icon :left="rtl" :right="!rtl" size="18" class="ml-2" dark>diamond</v-icon>
</v-btn>
</p>
<p class="body-1 pt-2">
<a target="_blank" href="https://link.photoprism.app/github">
<translate>Also, please leave a star on GitHub if you like this project. It provides additional motivation to keep going.</translate>
</a>
</div>
<div v-else-if="isAdmin && !isSponsor">
<p class="text-xs-center my-4">
<v-btn
to="/upgrade"
color="primary-button"
class="white--text px-3 py-2 action-upgrade"
round depressed
>
<translate>Upgrade Now</translate>
<v-icon :left="rtl" :right="!rtl" size="18" class="ml-2" dark>diamond</v-icon>
</v-btn>
</p>
</div>
@ -77,12 +79,12 @@
</ul>
<p class="body-1 text-selectable pb-2">
<a target="_blank" href="https://photoprism.app/contact"><translate>In addition, sponsors receive direct technical support via email.</translate></a>
<span v-if="!sponsor">
<span v-if="!isSponsor">
<translate>We'll do our best to answer all your questions. In return, we ask you to back us on Patreon or GitHub Sponsors.</translate>
</span>
</p>
<p v-if="sponsor" class="text-xs-center">
<p v-if="isSponsor" class="text-xs-center">
<img src="https://cdn.photoprism.app/thank-you/colorful.png" width="100%" alt="THANK YOU">
</p>
@ -123,7 +125,10 @@ export default {
data() {
return {
rtl: this.$rtl,
sponsor: this.$config.isSponsor(),
isPublic: this.$config.isPublic(),
isAdmin: this.$session.isAdmin(),
isDemo: this.$config.isDemo(),
isSponsor: this.$config.isSponsor(),
};
},
methods: {},

View file

@ -81,7 +81,11 @@ export default {
},
created() {
this.$config.load().then(() => {
if (this.$config.isPublic() || !this.$session.isAdmin()) {
this.$router.push({name: "home"});
} else {
this.send();
}
});
},
methods: {
@ -112,7 +116,7 @@ export default {
});
} else {
this.$notify.error(this.$gettext("Invalid parameters"));
this.$router.push({name: "settings"});
this.$router.push({name: "upgrade"});
}
},

View file

@ -86,14 +86,14 @@
</v-flex>
<v-flex xs12 sm6 class="pa-0 body-2 text-xs-center text-sm-right white--text">
<v-btn
href="https://link.photoprism.app/membership"
href="https://photoprism.app/"
target="_blank"
color="transparent"
class="white--text px-3 py-2 ma-0 action-sponsor"
class="white--text px-3 py-2 ma-0 action-about"
round depressed small
>
<translate>Become a sponsor</translate>
<v-icon :left="rtl" :right="!rtl" size="16" class="ml-2" dark>star</v-icon>
<translate>Learn more</translate>
<v-icon :left="rtl" :right="!rtl" size="16" class="ml-2" dark>diamond</v-icon>
</v-btn>
</v-flex>
</v-layout>

View file

@ -0,0 +1,134 @@
<template>
<div class="p-page p-page-upgrade">
<v-toolbar flat color="secondary" :dense="$vuetify.breakpoint.smAndDown">
<v-toolbar-title>
<translate>Support Our Mission</translate>
</v-toolbar-title>
<v-spacer></v-spacer>
<v-btn icon href="https://link.photoprism.app/personal-editions" target="_blank" class="action-upgrade" :title="$gettext('Upgrade')">
<v-icon size="26">diamond</v-icon>
</v-btn>
</v-toolbar>
<v-form ref="form" v-model="valid" autocomplete="off" class="px-3 pt-3 pb-0" lazy-validation>
<v-layout row wrap>
<v-flex xs12 class="px-2 pt-2 pb-0">
<p class="subheading text-selectable">
<strong><translate>Upgrade now and enjoy our member benefits!</translate></strong>
</p>
<p class="subheading text-selectable">
<translate>Your continued support helps us provide regular updates and remain independent, so we can fulfill our mission and protect your privacy.</translate>
<translate>To upgrade, you may either enter an activation code or click on "Sign Up" to upgrade on our website:</translate>
</p>
</v-flex>
<v-flex xs12 class="pa-2">
<v-text-field v-model="form.token" flat solo hide-details return-masked-value :mask="tokenMask"
browser-autocomplete="off"
color="secondary-dark"
background-color="secondary-light" :label="$gettext('Activation Code')" type="text">
</v-text-field>
</v-flex>
<v-flex xs12 grow class="px-2 py-1">
<v-btn color="secondary-light" :block="$vuetify.breakpoint.xsOnly"
class="ml-0"
depressed
:disabled="busy"
@click.stop="compare">
<translate>Compare Features</translate>
</v-btn>
<v-btn v-if="form.token.length < 1" color="primary-button"
class="white--text ml-0" :block="$vuetify.breakpoint.xsOnly"
depressed
:disabled="busy"
@click.stop="upgrade">
<translate>Sign Up</translate>
<v-icon :right="!rtl" :left="rtl" dark>navigate_next</v-icon>
</v-btn>
<v-btn v-else color="primary-button" :block="$vuetify.breakpoint.xsOnly"
class="white--text ml-0"
depressed
:disabled="busy || form.token.length < 4"
@click.stop="activate">
<translate>Activate</translate>
<v-icon :right="!rtl" :left="rtl" dark>navigate_next</v-icon>
</v-btn>
</v-flex>
<v-flex xs12 class="px-2 pt-3 pb-0">
<p class="body-1 text-selectable">
<translate>Feel free to contact us at hello@photoprism.app if you have any questions.</translate>
</p>
</v-flex>
<v-flex xs12 class="px-2 pt-3 pb-0">
<h3 class="pb-3"><translate>Frequently Asked Questions</translate></h3>
<p class="body-2 text-selectable">
<translate>Shouldn't free software be free of costs?</translate>
</p>
<p class="body-1 text-selectable">
<translate>Think of free software as in free speech, not as in free beer. The Free Software Foundation sometimes calls it libre software, borrowing the French or Spanish word for free as in freedom, to show they do not mean the software is gratis.</translate>
</p>
<p class="body-2 text-selectable">
<translate>Why are some features only available to sponsors?</translate>
</p>
<p class="body-1 text-selectable">
<translate>PhotoPrism is 100% self-funded. Voluntary donations do not cover the cost of a team working full time to provide you with updates, documentation, and support. It is your decision whether you want to sign up to enjoy additional benefits.</translate>
</p>
<p class="body-2 text-selectable">
<translate>What functionality is generally available?</translate>
</p>
<p class="body-1 text-selectable">
<translate>Our team evaluates this on an ongoing basis, depending on the support effort features and config options cause or have caused in the past, and whether they are generally needed by everyone or mainly requested by organizations and advanced users. As this allows us to make more features available to the public, we encourage all users to support our mission.</translate>
</p>
<p><a href="https://link.photoprism.app/membership" class="text-link" target="_blank"><translate>Learn more</translate> </a></p>
</v-flex>
</v-layout>
</v-form>
<p-about-footer></p-about-footer>
</div>
</template>
<script>
import * as options from "options/options";
export default {
name: 'PPageUpgrade',
data() {
return {
success: false,
busy: false,
valid: false,
error: "",
options: options,
isPublic: this.$config.isPublic(),
isAdmin: this.$session.isAdmin(),
isDemo: this.$config.isDemo(),
isSponsor: this.$config.isSponsor(),
rtl: this.$rtl,
tokenMask: 'nnnn-nnnn-nnnn',
form: {
name: "hub",
token: "",
},
};
},
created() {
this.$config.load().then(() => {
if (this.$config.isPublic() || !this.$session.isAdmin()) {
this.$router.push({name: "home"});
}
});
},
methods: {
compare() {
window.open('https://link.photoprism.app/personal-editions', '_blank').focus();
},
upgrade() {
window.location ='https://my.photoprism.app/register?upgrade='+encodeURIComponent(window.location);
},
activate() {
this.$router.push({name: "connect", params: {name:"hub",token:""}});
}
},
};
</script>

2
go.mod
View file

@ -81,7 +81,7 @@ require (
github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 // indirect
github.com/aws/aws-sdk-go v1.44.115 // indirect
github.com/cloudflare/cloudflare-go v0.52.0 // indirect
github.com/go-acme/lego/v4 v4.9.0
github.com/go-acme/lego/v4 v4.9.1
github.com/golang-jwt/jwt/v4 v4.4.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect

4
go.sum
View file

@ -382,8 +382,8 @@ github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjX
github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8=
github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-acme/lego/v4 v4.9.0 h1:8Hjj44IqRS7cigshMyFQ+0pIZvwgkG/+9A0UnNh7G8A=
github.com/go-acme/lego/v4 v4.9.0/go.mod h1:g3JRUyWS3L/VObpp4bCxzJftKyf/Wba8QrSSnoiqjg4=
github.com/go-acme/lego/v4 v4.9.1 h1:n9Z5MQwANeGSQKlVE3bEh9SDvAySK9oVYOKCGCESqQE=
github.com/go-acme/lego/v4 v4.9.1/go.mod h1:g3JRUyWS3L/VObpp4bCxzJftKyf/Wba8QrSSnoiqjg4=
github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A=
github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs=

View file

@ -71,6 +71,7 @@ type ClientConfig struct {
Countries entity.Countries `json:"countries"`
People entity.People `json:"people"`
Thumbs ThumbSizes `json:"thumbs"`
Customer string `json:"customer"`
MapKey string `json:"mapKey"`
DownloadToken string `json:"downloadToken,omitempty"`
PreviewToken string `json:"previewToken,omitempty"`
@ -355,6 +356,7 @@ func (c *Config) ClientShare() ClientConfig {
Colors: colors.All.List(),
Thumbs: Thumbs,
MapKey: c.Hub().MapKey(),
Customer: c.Hub().Customer(),
DownloadToken: c.DownloadToken(),
PreviewToken: c.PreviewToken(),
ManifestUri: c.ClientManifestUri(),
@ -441,6 +443,7 @@ func (c *Config) ClientUser(withSettings bool) ClientConfig {
Colors: colors.All.List(),
Thumbs: Thumbs,
MapKey: c.Hub().MapKey(),
Customer: c.Hub().Customer(),
DownloadToken: c.DownloadToken(),
PreviewToken: c.PreviewToken(),
ManifestUri: c.ClientManifestUri(),

View file

@ -727,7 +727,7 @@ func (c *Config) UpdateHub() {
// ResyncHub renews backend api credentials for maps & places with an optional token.
func (c *Config) ResyncHub(token string) error {
if err := c.hub.Resync(token); err != nil {
if err := c.hub.ReSync(token); err != nil {
log.Debugf("config: %s (refresh backend api tokens)", err)
if token != "" {
return i18n.Error(i18n.ErrAccountConnect)

View file

@ -14,6 +14,7 @@ import (
"os"
"path/filepath"
"strings"
"sync"
"time"
"gopkg.in/yaml.v2"
@ -36,6 +37,8 @@ type Config struct {
Key string `json:"key" yaml:"Key"`
Secret string `json:"secret" yaml:"Secret"`
Session string `json:"session" yaml:"Session"`
session *Session `json:"-" yaml:"-"`
sessionMu sync.Mutex `json:"-" yaml:"-"`
Status string `json:"status" yaml:"Status"`
Serial string `json:"serial" yaml:"Serial"`
Env string `json:"-" yaml:"-"`
@ -61,13 +64,22 @@ func NewConfig(version, fileName, serial, env, userAgent, partnerId string) *Con
// MapKey returns the maps api key.
func (c *Config) MapKey() string {
if sess, err := c.DecodeSession(); err != nil {
if sess, err := c.DecodeSession(true); err != nil {
return ""
} else {
return sess.MapKey
}
}
// Customer returns the customer name.
func (c *Config) Customer() string {
if sess, err := c.DecodeSession(true); err != nil {
return ""
} else {
return sess.Customer
}
}
// Propagate updates backend api credentials in other packages.
func (c *Config) Propagate() {
places.Key = c.Key
@ -99,15 +111,28 @@ func (c *Config) Sanitize() {
}
// DecodeSession decodes backend api session data.
func (c *Config) DecodeSession() (Session, error) {
func (c *Config) DecodeSession(cached bool) (Session, error) {
c.sessionMu.Lock()
defer c.sessionMu.Unlock()
c.Sanitize()
result := Session{}
// No session?
if c.Session == "" {
return result, fmt.Errorf("empty session")
c.session = nil
return Session{}, fmt.Errorf("empty session")
}
if cached && c.session != nil {
// Return cached session.
return *c.session, nil
} else {
// Clear session cache.
c.session = nil
}
result := Session{}
s, err := hex.DecodeString(c.Session)
if err != nil {
@ -140,20 +165,27 @@ func (c *Config) DecodeSession() (Session, error) {
return result, err
}
// Cache session.
c.session = &result
return result, nil
}
// Update renews backend api credentials without a token.
func (c *Config) Update() error {
return c.Resync("")
return c.ReSync("")
}
// Resync renews backend api credentials with an optional token.
func (c *Config) Resync(token string) (err error) {
// ReSync renews backend api credentials with an optional token.
func (c *Config) ReSync(token string) (err error) {
mutex.Lock()
defer mutex.Unlock()
if err := os.MkdirAll(filepath.Dir(c.FileName), fs.ModeDir); err != nil {
// Clear session.
c.session = nil
// Make sure storage folder exists.
if err = os.MkdirAll(filepath.Dir(c.FileName), fs.ModeDir); err != nil {
return err
}
@ -251,7 +283,7 @@ func (c *Config) Load() error {
c.Sanitize()
c.Propagate()
if sess, err := c.DecodeSession(); err != nil {
if sess, err := c.DecodeSession(false); err != nil {
return err
} else if sess.Expired() {
return errors.New("session expired")

View file

@ -82,10 +82,12 @@ func TestConfig_Refresh(t *testing.T) {
assert.Len(t, c.Secret, 32)
assert.Equal(t, "0.0.0", c.Version)
if sess, err := c.DecodeSession(); err != nil {
if sess, err := c.DecodeSession(false); err != nil {
t.Fatal(err)
} else if sess.Expired() {
t.Fatalf("session expired: %+v", sess)
} else {
t.Logf("(1) session: %#v", sess)
}
if err := c.Save(); err != nil {
@ -104,18 +106,18 @@ func TestConfig_Refresh(t *testing.T) {
assert.Len(t, c.Secret, 32)
assert.Equal(t, "0.0.0", c.Version)
if sess, err := c.DecodeSession(); err != nil {
if sess, err := c.DecodeSession(false); err != nil {
t.Fatal(err)
} else if sess.Expired() {
t.Fatal("session expired")
} else {
t.Logf("api session: %+v", sess)
t.Logf("(2) session: %#v", sess)
}
if err := c.Save(); err != nil {
t.Fatal(err)
}
t.Logf("filename: %s", fileName)
assert.FileExists(t, fileName)
})
}

View file

@ -5,6 +5,7 @@ import "time"
// Session represents backend api session data.
type Session struct {
MapKey string
Customer string `json:",omitempty"`
ExpiresAt string
}