Signed-off-by: Michael Mayer <michael@liquidbytes.net>
This commit is contained in:
parent
53c48cd570
commit
33888fd231
15 changed files with 469 additions and 125 deletions
|
@ -138,9 +138,9 @@ export default class Session {
|
|||
return "";
|
||||
}
|
||||
|
||||
getFirstName() {
|
||||
getGivenName() {
|
||||
if (this.isUser()) {
|
||||
return this.user.FirstName;
|
||||
return this.user.GivenName;
|
||||
}
|
||||
|
||||
return "";
|
||||
|
@ -148,7 +148,7 @@ export default class Session {
|
|||
|
||||
getFullName() {
|
||||
if (this.isUser()) {
|
||||
return this.user.FirstName + " " + this.user.LastName;
|
||||
return this.user.GivenName + " " + this.user.FamilyName;
|
||||
}
|
||||
|
||||
return "";
|
||||
|
@ -159,7 +159,7 @@ export default class Session {
|
|||
}
|
||||
|
||||
isAdmin() {
|
||||
return this.user && this.user.hasId() && this.user.Admin;
|
||||
return this.user && this.user.hasId() && this.user.RoleAdmin;
|
||||
}
|
||||
|
||||
isAnonymous() {
|
||||
|
|
|
@ -38,28 +38,81 @@ export class User extends RestModel {
|
|||
return {
|
||||
ID: 0,
|
||||
UID: "",
|
||||
ParentUID: "",
|
||||
UserUUID: "",
|
||||
UserName: "",
|
||||
FirstName: "",
|
||||
LastName: "",
|
||||
UserLocale: "",
|
||||
TimeZone: "",
|
||||
PrimaryEmail: "",
|
||||
BackupEmail: "",
|
||||
DisplayName: "",
|
||||
Email: "",
|
||||
Info: "",
|
||||
Notes: "",
|
||||
Active: false,
|
||||
Confirmed: false,
|
||||
Admin: false,
|
||||
Guest: false,
|
||||
Child: false,
|
||||
Family: false,
|
||||
Friend: false,
|
||||
Artist: false,
|
||||
Subject: false,
|
||||
DisplayLocation: "",
|
||||
DisplayBio: "",
|
||||
NamePrefix: "",
|
||||
GivenName: "",
|
||||
FamilyName: "",
|
||||
NameSuffix: "",
|
||||
AvatarUID: "",
|
||||
AvatarURL: "",
|
||||
FeedURL: "",
|
||||
FeedType: "",
|
||||
FeedFollow: false,
|
||||
BlogURL: "",
|
||||
BlogType: "",
|
||||
BlogFollow: false,
|
||||
CompanyURL: "",
|
||||
CompanyName: "",
|
||||
CompanyPhone: "",
|
||||
PrimaryPhone: "",
|
||||
DepartmentName: "",
|
||||
JobTitle: "",
|
||||
AddressLat: 0.0,
|
||||
AddressLng: 0.0,
|
||||
AddressLine1: "",
|
||||
AddressLine2: "",
|
||||
AddressZip: "",
|
||||
AddressCity: "",
|
||||
AddressState: "",
|
||||
AddressCountry: "",
|
||||
TermsAccepted: false,
|
||||
IsActive: false,
|
||||
IsConfirmed: false,
|
||||
IsPro: false,
|
||||
IsSponsor: false,
|
||||
IsContributor: false,
|
||||
IsArtist: false,
|
||||
IsSubject: false,
|
||||
RoleAdmin: false,
|
||||
RoleGuest: false,
|
||||
RoleChild: false,
|
||||
RoleFamily: false,
|
||||
RoleFriend: false,
|
||||
CanEdit: false,
|
||||
CanDelete: false,
|
||||
CanIndex: false,
|
||||
CanShare: false,
|
||||
CanComment: false,
|
||||
CanUpload: false,
|
||||
CanDownload: false,
|
||||
WebDAV: false,
|
||||
ApiToken: "",
|
||||
AmazonID: "",
|
||||
AppleID: "",
|
||||
EyeEmID: "",
|
||||
FacebookID: "",
|
||||
FlickrID: "",
|
||||
GitHubID: "",
|
||||
GitLabID: "",
|
||||
GoogleID: "",
|
||||
InstagramID: "",
|
||||
LinkedinID: "",
|
||||
MastodonID: "",
|
||||
NextcloudID: "",
|
||||
TelegramID: "",
|
||||
TwitterID: "",
|
||||
WhatsAppID: "",
|
||||
YouTubeID: "",
|
||||
UserNotes: "",
|
||||
LoginAttempts: 0,
|
||||
LoginAt: "",
|
||||
CreatedAt: "",
|
||||
|
@ -68,7 +121,7 @@ export class User extends RestModel {
|
|||
}
|
||||
|
||||
getEntityName() {
|
||||
return this.FirstName + " " + this.LastName;
|
||||
return this.GivenName + " " + this.FamilyName;
|
||||
}
|
||||
|
||||
getRegisterForm() {
|
||||
|
|
|
@ -185,12 +185,12 @@ describe('common/session', () => {
|
|||
const storage = window.localStorage;
|
||||
const session = new Session(storage, config);
|
||||
assert.isFalse(session.user.hasId());
|
||||
const values = {"user": {ID: 5, FirstName: "Max", LastName: "Last", Email: "test@test.com", Admin: true}};
|
||||
const values = {"user": {ID: 5, GivenName: "Max", FamilyName: "Last", Email: "test@test.com", RoleAdmin: true}};
|
||||
session.setData();
|
||||
assert.equal(session.user.FirstName, "");
|
||||
assert.equal(session.user.GivenName, "");
|
||||
session.setData(values);
|
||||
assert.equal(session.user.FirstName, "Max");
|
||||
assert.equal(session.user.Admin, true);
|
||||
assert.equal(session.user.GivenName, "Max");
|
||||
assert.equal(session.user.RoleAdmin, true);
|
||||
const result = session.getUser();
|
||||
assert.equal(result.ID, 5);
|
||||
assert.equal(result.Email, "test@test.com");
|
||||
|
@ -201,11 +201,11 @@ describe('common/session', () => {
|
|||
it('should get user email', () => {
|
||||
const storage = window.localStorage;
|
||||
const session = new Session(storage, config);
|
||||
const values = {"user": {ID: 5, FirstName: "Max", LastName: "Last", Email: "test@test.com", Admin: true}};
|
||||
const values = {"user": {ID: 5, GivenName: "Max", FamilyName: "Last", Email: "test@test.com", RoleAdmin: true}};
|
||||
session.setData(values);
|
||||
const result = session.getEmail();
|
||||
assert.equal(result, "test@test.com");
|
||||
const values2 = {"user": {FirstName: "Max", LastName: "Last", Email: "test@test.com", Admin: true}};
|
||||
const values2 = {"user": {GivenName: "Max", FamilyName: "Last", Email: "test@test.com", RoleAdmin: true}};
|
||||
session.setData(values2);
|
||||
const result2 = session.getEmail();
|
||||
assert.equal(result2, "");
|
||||
|
@ -215,13 +215,13 @@ describe('common/session', () => {
|
|||
it('should get user firstname', () => {
|
||||
const storage = window.localStorage;
|
||||
const session = new Session(storage, config);
|
||||
const values = {"user": {ID: 5, FirstName: "Max", LastName: "Last", Email: "test@test.com", Admin: true}};
|
||||
const values = {"user": {ID: 5, GivenName: "Max", FamilyName: "Last", Email: "test@test.com", RoleAdmin: true}};
|
||||
session.setData(values);
|
||||
const result = session.getFirstName();
|
||||
const result = session.getGivenName();
|
||||
assert.equal(result, "Max");
|
||||
const values2 = {"user": {FirstName: "Max", LastName: "Last", Email: "test@test.com", Admin: true}};
|
||||
const values2 = {"user": {GivenName: "Max", FamilyName: "Last", Email: "test@test.com", RoleAdmin: true}};
|
||||
session.setData(values2);
|
||||
const result2 = session.getFirstName();
|
||||
const result2 = session.getGivenName();
|
||||
assert.equal(result2, "");
|
||||
session.deleteData();
|
||||
});
|
||||
|
@ -229,11 +229,11 @@ describe('common/session', () => {
|
|||
it('should get user full name', () => {
|
||||
const storage = window.localStorage;
|
||||
const session = new Session(storage, config);
|
||||
const values = {"user": {ID: 5, FirstName: "Max", LastName: "Last", Email: "test@test.com", Admin: true}};
|
||||
const values = {"user": {ID: 5, GivenName: "Max", FamilyName: "Last", Email: "test@test.com", RoleAdmin: true}};
|
||||
session.setData(values);
|
||||
const result = session.getFullName();
|
||||
assert.equal(result, "Max Last");
|
||||
const values2 = {"user": {FirstName: "Max", LastName: "Last", Email: "test@test.com", Admin: true}};
|
||||
const values2 = {"user": {GivenName: "Max", FamilyName: "Last", Email: "test@test.com", RoleAdmin: true}};
|
||||
session.setData(values2);
|
||||
const result2 = session.getFullName();
|
||||
assert.equal(result2, "");
|
||||
|
@ -243,7 +243,7 @@ describe('common/session', () => {
|
|||
it('should test whether user is set', () => {
|
||||
const storage = window.localStorage;
|
||||
const session = new Session(storage, config);
|
||||
const values = {"user": {ID: 5, FirstName: "Max", LastName: "Last", Email: "test@test.com", Admin: true}};
|
||||
const values = {"user": {ID: 5, GivenName: "Max", FamilyName: "Last", Email: "test@test.com", RoleAdmin: true}};
|
||||
session.setData(values);
|
||||
const result = session.isUser();
|
||||
assert.equal(result, true);
|
||||
|
@ -253,7 +253,7 @@ describe('common/session', () => {
|
|||
it('should test whether user is admin', () => {
|
||||
const storage = window.localStorage;
|
||||
const session = new Session(storage, config);
|
||||
const values = {"user": {ID: 5, FirstName: "Max", LastName: "Last", Email: "test@test.com", Admin: true}};
|
||||
const values = {"user": {ID: 5, GivenName: "Max", FamilyName: "Last", Email: "test@test.com", RoleAdmin: true}};
|
||||
session.setData(values);
|
||||
const result = session.isAdmin();
|
||||
assert.equal(result, true);
|
||||
|
@ -263,7 +263,7 @@ describe('common/session', () => {
|
|||
it('should test whether user is anonymous', () => {
|
||||
const storage = window.localStorage;
|
||||
const session = new Session(storage, config);
|
||||
const values = {"user": {ID: 5, FirstName: "Max", LastName: "Last", Email: "test@test.com", Admin: true}};
|
||||
const values = {"user": {ID: 5, GivenName: "Max", FamilyName: "Last", Email: "test@test.com", RoleAdmin: true}};
|
||||
session.setData(values);
|
||||
const result = session.isAnonymous();
|
||||
assert.equal(result, false);
|
||||
|
|
|
@ -9,14 +9,14 @@ describe("model/user", () => {
|
|||
const mock = new MockAdapter(Api);
|
||||
|
||||
it("should get entity name", () => {
|
||||
const values = {ID: 5, FirstName: "Max", LastName: "Last", Email: "test@test.com", Role: "admin"};
|
||||
const values = {ID: 5, GivenName: "Max", FamilyName: "Last", Email: "test@test.com", Role: "admin"};
|
||||
const user = new User(values);
|
||||
const result = user.getEntityName();
|
||||
assert.equal(result, "Max Last");
|
||||
});
|
||||
|
||||
it("should get id", () => {
|
||||
const values = {ID: 5, FirstName: "Max", LastName: "Last", Email: "test@test.com", Role: "admin"};
|
||||
const values = {ID: 5, GivenName: "Max", FamilyName: "Last", Email: "test@test.com", Role: "admin"};
|
||||
const user = new User(values);
|
||||
const result = user.getId();
|
||||
assert.equal(result, 5);
|
||||
|
@ -34,7 +34,7 @@ describe("model/user", () => {
|
|||
|
||||
it("should get register form", async() => {
|
||||
mock.onAny("users/52/register").reply(200, "registerForm");
|
||||
const values = {ID: 52, FirstName: "Max"};
|
||||
const values = {ID: 52, GivenName: "Max"};
|
||||
const user = new User(values);
|
||||
const result = await user.getRegisterForm();
|
||||
assert.equal(result.definition, "registerForm");
|
||||
|
@ -43,7 +43,7 @@ describe("model/user", () => {
|
|||
|
||||
it("should get profile form", async() => {
|
||||
mock.onAny("users/53/profile").reply(200, "profileForm");
|
||||
const values = {ID: 53, FirstName: "Max"};
|
||||
const values = {ID: 53, GivenName: "Max"};
|
||||
const user = new User(values);
|
||||
const result = await user.getProfileForm();
|
||||
assert.equal(result.definition, "profileForm");
|
||||
|
@ -52,20 +52,20 @@ describe("model/user", () => {
|
|||
|
||||
it("should get change password", async() => {
|
||||
mock.onPut("users/54/password").reply(200, {password: "old", new_password: "new"});
|
||||
const values = {ID: 54, FirstName: "Max", LastName: "Last", Email: "test@test.com", Role: "admin"};
|
||||
const values = {ID: 54, GivenName: "Max", FamilyName: "Last", Email: "test@test.com", Role: "admin"};
|
||||
const user = new User(values);
|
||||
const result = await user.changePassword("old", "new");
|
||||
assert.equal(result.new_password, "new");
|
||||
});
|
||||
|
||||
it("should save profile", async() => {
|
||||
mock.onPost("users/55/profile").reply(200, {FirstName: "MaxNew", LastName: "LastNew"});
|
||||
const values = {ID: 55, FirstName: "Max", LastName: "Last", Email: "test@test.com", Role: "admin"};
|
||||
mock.onPost("users/55/profile").reply(200, {GivenName: "MaxNew", FamilyName: "LastNew"});
|
||||
const values = {ID: 55, GivenName: "Max", FamilyName: "Last", Email: "test@test.com", Role: "admin"};
|
||||
const user = new User(values);
|
||||
assert.equal(user.FirstName, "Max");
|
||||
assert.equal(user.LastName, "Last");
|
||||
assert.equal(user.GivenName, "Max");
|
||||
assert.equal(user.FamilyName, "Last");
|
||||
await user.saveProfile();
|
||||
assert.equal(user.FirstName, "MaxNew");
|
||||
assert.equal(user.LastName, "LastNew");
|
||||
assert.equal(user.GivenName, "MaxNew");
|
||||
assert.equal(user.FamilyName, "LastNew");
|
||||
});
|
||||
});
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
"github.com/photoprism/photoprism/pkg/txt"
|
||||
)
|
||||
|
||||
// ClientConfig contains HTTP client / Web UI config values
|
||||
// ClientConfig represents HTTP client / Web UI config values.
|
||||
type ClientConfig struct {
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
|
@ -26,6 +26,9 @@ type ClientConfig struct {
|
|||
ReadOnly bool `json:"readonly"`
|
||||
UploadNSFW bool `json:"uploadNSFW"`
|
||||
Public bool `json:"public"`
|
||||
Pro bool `json:"pro"`
|
||||
Sponsor bool `json:"sponsor"`
|
||||
Contributor bool `json:"contributor"`
|
||||
Experimental bool `json:"experimental"`
|
||||
DisableSettings bool `json:"disableSettings"`
|
||||
AlbumCategories []string `json:"albumCategories"`
|
||||
|
@ -34,6 +37,8 @@ type ClientConfig struct {
|
|||
Lenses []entity.Lens `json:"lenses"`
|
||||
Countries []entity.Country `json:"countries"`
|
||||
Thumbs []Thumb `json:"thumbs"`
|
||||
ApiKey string `json:"apiKey"`
|
||||
MapsKey string `json:"mapsKey"`
|
||||
DownloadToken string `json:"downloadToken"`
|
||||
PreviewToken string `json:"previewToken"`
|
||||
JSHash string `json:"jsHash"`
|
||||
|
|
|
@ -2,6 +2,7 @@ package config
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
|
@ -11,6 +12,7 @@ import (
|
|||
_ "github.com/jinzhu/gorm/dialects/mysql"
|
||||
_ "github.com/jinzhu/gorm/dialects/sqlite"
|
||||
"github.com/photoprism/photoprism/internal/event"
|
||||
"github.com/photoprism/photoprism/internal/maps/places"
|
||||
"github.com/photoprism/photoprism/internal/mutex"
|
||||
"github.com/photoprism/photoprism/internal/thumb"
|
||||
"github.com/photoprism/photoprism/pkg/rnd"
|
||||
|
@ -23,11 +25,12 @@ var once sync.Once
|
|||
|
||||
// Config holds database, cache and all parameters of photoprism
|
||||
type Config struct {
|
||||
once sync.Once
|
||||
db *gorm.DB
|
||||
params *Params
|
||||
settings *Settings
|
||||
token string
|
||||
once sync.Once
|
||||
db *gorm.DB
|
||||
params *Params
|
||||
settings *Settings
|
||||
credentials *Credentials
|
||||
token string
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
@ -67,6 +70,7 @@ func NewConfig(ctx *cli.Context) *Config {
|
|||
}
|
||||
|
||||
c.initSettings()
|
||||
c.initCredentials()
|
||||
|
||||
return c
|
||||
}
|
||||
|
@ -79,12 +83,14 @@ func (c *Config) Propagate() {
|
|||
thumb.SizeUncached = c.ThumbSizeUncached()
|
||||
thumb.Filter = c.ThumbFilter()
|
||||
thumb.JpegQuality = c.JpegQuality()
|
||||
places.UserAgent = c.UserAgent()
|
||||
|
||||
c.Settings().Propagate()
|
||||
c.Credentials().Propagate()
|
||||
}
|
||||
|
||||
// Init initialises the database connection and dependencies.
|
||||
func (c *Config) Init(ctx context.Context) error {
|
||||
func (c *Config) Init(_ context.Context) error {
|
||||
c.Propagate()
|
||||
return c.connectDb()
|
||||
}
|
||||
|
@ -99,6 +105,11 @@ func (c *Config) Version() string {
|
|||
return c.params.Version
|
||||
}
|
||||
|
||||
// UserAgent returns a HTTP user agent string based on app name & version.
|
||||
func (c *Config) UserAgent() string {
|
||||
return fmt.Sprintf("%s/%s", c.Name(), c.Version())
|
||||
}
|
||||
|
||||
// Copyright returns the application copyright.
|
||||
func (c *Config) Copyright() string {
|
||||
return c.params.Copyright
|
||||
|
|
107
internal/config/credentials.go
Normal file
107
internal/config/credentials.go
Normal file
|
@ -0,0 +1,107 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/maps/places"
|
||||
"github.com/photoprism/photoprism/pkg/fs"
|
||||
"github.com/photoprism/photoprism/pkg/txt"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
// Credentials represents api credentials for hosted services like maps & places.
|
||||
type Credentials struct {
|
||||
Key string `json:"key" yaml:"key"`
|
||||
Secret string `json:"secret" yaml:"secret"`
|
||||
Session string `json:"session" yaml:"session"`
|
||||
}
|
||||
|
||||
// NewCredentials creates a new Credentials instance.
|
||||
func NewCredentials() *Credentials {
|
||||
return &Credentials{
|
||||
Key: "",
|
||||
Secret: "",
|
||||
Session: "",
|
||||
}
|
||||
}
|
||||
|
||||
// Propagate updates api credentials in other packages.
|
||||
func (a *Credentials) Propagate() {
|
||||
places.Key = a.Key
|
||||
}
|
||||
|
||||
// Sanitize verifies and sanitizes api credentials;
|
||||
func (a *Credentials) Sanitize() {
|
||||
a.Key = strings.ToLower(a.Key)
|
||||
|
||||
if a.Secret != "" {
|
||||
if a.Key != fmt.Sprintf("%x", sha1.Sum([]byte(a.Secret))) {
|
||||
a.Secret = ""
|
||||
a.Session = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load api credentials from a file.
|
||||
func (a *Credentials) Load(fileName string) error {
|
||||
if !fs.FileExists(fileName) {
|
||||
return fmt.Errorf("credentials file not found: %s", txt.Quote(fileName))
|
||||
}
|
||||
|
||||
yamlConfig, err := ioutil.ReadFile(fileName)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := yaml.Unmarshal(yamlConfig, a); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.Sanitize()
|
||||
a.Propagate()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Save api credentials to a file.
|
||||
func (a *Credentials) Save(fileName string) error {
|
||||
a.Sanitize()
|
||||
|
||||
data, err := yaml.Marshal(a)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.Propagate()
|
||||
|
||||
if err := ioutil.WriteFile(fileName, data, os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.Propagate()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// initCredentials initializes the api credentials.
|
||||
func (c *Config) initCredentials() {
|
||||
c.credentials = NewCredentials()
|
||||
p := c.CredentialsFile()
|
||||
|
||||
if err := c.credentials.Load(p); err != nil {
|
||||
log.Traceln(err)
|
||||
}
|
||||
|
||||
c.credentials.Propagate()
|
||||
}
|
||||
|
||||
// Credentials returns the api key instance.
|
||||
func (c *Config) Credentials() *Credentials {
|
||||
return c.credentials
|
||||
}
|
84
internal/config/credentials_test.go
Normal file
84
internal/config/credentials_test.go
Normal file
|
@ -0,0 +1,84 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewCredentials(t *testing.T) {
|
||||
c := NewCredentials()
|
||||
|
||||
assert.IsType(t, &Credentials{}, c)
|
||||
}
|
||||
|
||||
func TestCredentials_Load(t *testing.T) {
|
||||
t.Run("existing filename", func(t *testing.T) {
|
||||
c := NewCredentials()
|
||||
|
||||
if err := c.Load("testdata/credentials.yml"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assert.Equal(t, "f60f5b25d59c397989e3cd374f81cdd7710a4fca", c.Key)
|
||||
assert.Equal(t, "photoprism", c.Secret)
|
||||
assert.Equal(t, "Zm9vYmFy", c.Session)
|
||||
})
|
||||
t.Run("not existing filename", func(t *testing.T) {
|
||||
c := NewCredentials()
|
||||
|
||||
if err := c.Load("testdata/credentials_xxx.yml"); err == nil {
|
||||
t.Fatal("file should not exist")
|
||||
}
|
||||
|
||||
assert.Equal(t, "", c.Key)
|
||||
assert.Equal(t, "", c.Secret)
|
||||
assert.Equal(t, "", c.Session)
|
||||
})
|
||||
}
|
||||
func TestCredentials_Save(t *testing.T) {
|
||||
t.Run("existing filename", func(t *testing.T) {
|
||||
assert.FileExists(t, "testdata/credentials.yml")
|
||||
|
||||
c := NewCredentials()
|
||||
|
||||
if err := c.Load("testdata/credentials.yml"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assert.Equal(t, "f60f5b25d59c397989e3cd374f81cdd7710a4fca", c.Key)
|
||||
assert.Equal(t, "photoprism", c.Secret)
|
||||
assert.Equal(t, "Zm9vYmFy", c.Session)
|
||||
|
||||
if err := c.Save("testdata/credentials.yml"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assert.FileExists(t, "testdata/credentials.yml")
|
||||
})
|
||||
t.Run("not existing filename", func(t *testing.T) {
|
||||
c := NewCredentials()
|
||||
c.Key = "F60F5B25D59C397989E3CD374F81CDD7710A4FCA"
|
||||
c.Secret = "foo"
|
||||
c.Session = "bar"
|
||||
|
||||
assert.Equal(t, "F60F5B25D59C397989E3CD374F81CDD7710A4FCA", c.Key)
|
||||
assert.Equal(t, "foo", c.Secret)
|
||||
assert.Equal(t, "bar", c.Session)
|
||||
|
||||
if err := c.Save("testdata/credentials_new.yml"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assert.Equal(t, "f60f5b25d59c397989e3cd374f81cdd7710a4fca", c.Key)
|
||||
assert.Equal(t, "", c.Secret)
|
||||
assert.Equal(t, "", c.Session)
|
||||
|
||||
assert.FileExists(t, "testdata/credentials_new.yml")
|
||||
|
||||
if err := os.Remove("testdata/credentials_new.yml"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
}
|
|
@ -137,6 +137,11 @@ func (c *Config) ConfigFile() string {
|
|||
return c.params.ConfigFile
|
||||
}
|
||||
|
||||
// CredentialsFile returns the api credentials file name for hosted services like maps & places.
|
||||
func (c *Config) CredentialsFile() string {
|
||||
return filepath.Join(c.SettingsPath(), "credentials.yml")
|
||||
}
|
||||
|
||||
// SettingsFile returns the user settings file name.
|
||||
func (c *Config) SettingsFile() string {
|
||||
return filepath.Join(c.SettingsPath(), "settings.yml")
|
||||
|
@ -194,7 +199,7 @@ func (c *Config) ExifToolBin() string {
|
|||
return findExecutable(c.params.ExifToolBin, "exiftool")
|
||||
}
|
||||
|
||||
// SidecarJson returns true if metadata should be synced with json sidecar files as used by exiftool.
|
||||
// Automatically create JSON sidecar files using Exiftool.
|
||||
func (c *Config) SidecarJson() bool {
|
||||
if !c.SidecarWritable() || c.ExifToolBin() == "" {
|
||||
return false
|
||||
|
@ -203,7 +208,7 @@ func (c *Config) SidecarJson() bool {
|
|||
return c.params.SidecarJson
|
||||
}
|
||||
|
||||
// SidecarYaml returns true if metadata should be synced with PhotoPrism YAML sidecar files.
|
||||
// Automatically backup metadata to YAML sidecar files.
|
||||
func (c *Config) SidecarYaml() bool {
|
||||
if !c.SidecarWritable() {
|
||||
return false
|
||||
|
@ -212,7 +217,7 @@ func (c *Config) SidecarYaml() bool {
|
|||
return c.params.SidecarYaml
|
||||
}
|
||||
|
||||
// SidecarPath returns the storage path for automatically created sidecar files.
|
||||
// SidecarPath returns the storage path for generated sidecar files (relative or absolute).
|
||||
func (c *Config) SidecarPath() string {
|
||||
if c.params.SidecarPath == "" {
|
||||
c.params.SidecarPath = filepath.Join(c.StoragePath(), "sidecar")
|
||||
|
|
|
@ -16,15 +16,18 @@ func (c *Config) SettingsHidden() bool {
|
|||
return c.params.SettingsHidden
|
||||
}
|
||||
|
||||
// TemplateSettings represents HTML template settings for the Web UI.
|
||||
type TemplateSettings struct {
|
||||
Default string `json:"default" yaml:"default"`
|
||||
}
|
||||
|
||||
// MapsSettings represents maps settings (for places).
|
||||
type MapsSettings struct {
|
||||
Animate int `json:"animate" yaml:"animate"`
|
||||
Style string `json:"style" yaml:"style"`
|
||||
}
|
||||
|
||||
// IndexSettings represents indexing settings.
|
||||
type IndexSettings struct {
|
||||
Path string `json:"path" yaml:"path"`
|
||||
Convert bool `json:"convert" yaml:"convert"`
|
||||
|
@ -32,11 +35,13 @@ type IndexSettings struct {
|
|||
Sequences bool `json:"sequences" yaml:"sequences"`
|
||||
}
|
||||
|
||||
// ImportSettings represents import settings.
|
||||
type ImportSettings struct {
|
||||
Path string `json:"path" yaml:"path"`
|
||||
Move bool `json:"move" yaml:"move"`
|
||||
}
|
||||
|
||||
// FeatureSettings represents feature flags, mainly for the Web UI.
|
||||
type FeatureSettings struct {
|
||||
Upload bool `json:"upload" yaml:"upload"`
|
||||
Download bool `json:"download" yaml:"download"`
|
||||
|
@ -54,7 +59,7 @@ type FeatureSettings struct {
|
|||
Logs bool `json:"logs" yaml:"logs"`
|
||||
}
|
||||
|
||||
// Settings contains Web UI settings
|
||||
// Settings represents user settings for Web UI, indexing, and import.
|
||||
type Settings struct {
|
||||
Theme string `json:"theme" yaml:"theme"`
|
||||
Language string `json:"language" yaml:"language"`
|
||||
|
@ -65,7 +70,7 @@ type Settings struct {
|
|||
Index IndexSettings `json:"index" yaml:"index"`
|
||||
}
|
||||
|
||||
// NewSettings returns a empty Settings
|
||||
// NewSettings creates a new Settings instance.
|
||||
func NewSettings() *Settings {
|
||||
return &Settings{
|
||||
Theme: "default",
|
||||
|
@ -111,7 +116,7 @@ func (s Settings) Propagate() {
|
|||
i18n.SetLocale(s.Language)
|
||||
}
|
||||
|
||||
// Load uses a yaml config file to initiate the configuration entity.
|
||||
// Load user settings from file.
|
||||
func (s *Settings) Load(fileName string) error {
|
||||
if !fs.FileExists(fileName) {
|
||||
return fmt.Errorf("settings file not found: %s", txt.Quote(fileName))
|
||||
|
@ -132,7 +137,7 @@ func (s *Settings) Load(fileName string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Save uses a yaml config file to initiate the configuration entity.
|
||||
// Save user settings to a file.
|
||||
func (s *Settings) Save(fileName string) error {
|
||||
data, err := yaml.Marshal(s)
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
|
||||
func TestNewSettings(t *testing.T) {
|
||||
c := NewSettings()
|
||||
|
||||
assert.IsType(t, new(Settings), c)
|
||||
}
|
||||
|
||||
|
@ -16,9 +17,9 @@ func TestSettings_Load(t *testing.T) {
|
|||
t.Run("existing filename", func(t *testing.T) {
|
||||
c := NewSettings()
|
||||
|
||||
err := c.Load("testdata/config.yml")
|
||||
|
||||
assert.Nil(t, err)
|
||||
if err := c.Load("testdata/config.yml"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assert.Equal(t, "lavendel", c.Theme)
|
||||
assert.Equal(t, "english", c.Language)
|
||||
|
@ -43,9 +44,9 @@ func TestSettings_Save(t *testing.T) {
|
|||
assert.Equal(t, "lavendel", c.Theme)
|
||||
assert.Equal(t, "german", c.Language)
|
||||
|
||||
err := c.Save("testdata/configEmpty.yml")
|
||||
|
||||
assert.Nil(t, err)
|
||||
if err := c.Save("testdata/configEmpty.yml"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
t.Run("not existing filename", func(t *testing.T) {
|
||||
c := NewSettings()
|
||||
|
@ -55,9 +56,7 @@ func TestSettings_Save(t *testing.T) {
|
|||
assert.Equal(t, "lavendel", c.Theme)
|
||||
assert.Equal(t, "german", c.Language)
|
||||
|
||||
err := c.Save("testdata/configEmpty123.yml")
|
||||
|
||||
if err != nil {
|
||||
if err := c.Save("testdata/configEmpty123.yml"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
|
|
@ -130,6 +130,7 @@ func NewTestConfig() *Config {
|
|||
}
|
||||
|
||||
c.initSettings()
|
||||
c.initCredentials()
|
||||
|
||||
if err := c.Init(context.Background()); err != nil {
|
||||
log.Fatalf("config: %s", err.Error())
|
||||
|
@ -150,6 +151,7 @@ func NewTestErrorConfig() *Config {
|
|||
c := &Config{params: NewTestParamsError()}
|
||||
|
||||
c.initSettings()
|
||||
c.initCredentials()
|
||||
|
||||
if err := c.Init(context.Background()); err != nil {
|
||||
log.Fatalf("config: %s", err.Error())
|
||||
|
|
3
internal/config/testdata/credentials.yml
vendored
Normal file
3
internal/config/testdata/credentials.yml
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
key: f60f5b25d59c397989e3cd374f81cdd7710a4fca
|
||||
secret: photoprism
|
||||
session: Zm9vYmFy
|
|
@ -14,72 +14,138 @@ type People []Person
|
|||
|
||||
// Person represents a real person that can also be a user if a password is set.
|
||||
type Person struct {
|
||||
ID int `gorm:"primary_key" json:"ID" yaml:"-"`
|
||||
PersonUID string `gorm:"type:varbinary(42);unique_index;" json:"UID" yaml:"UID"`
|
||||
UserName string `gorm:"type:varchar(32);" json:"UserName" yaml:"UserName,omitempty"`
|
||||
FirstName string `gorm:"type:varchar(32);" json:"FirstName" yaml:"FirstName,omitempty"`
|
||||
LastName string `gorm:"type:varchar(32);" json:"LastName" yaml:"LastName,omitempty"`
|
||||
DisplayName string `gorm:"type:varchar(64);" json:"DisplayName" yaml:"DisplayName,omitempty"`
|
||||
UserEmail string `gorm:"type:varchar(255);" json:"Email" yaml:"Email,omitempty"`
|
||||
UserInfo string `gorm:"type:text;" json:"Info" yaml:"Info,omitempty"`
|
||||
UserPath string `json:"UserPath" yaml:"UserPath,omitempty"`
|
||||
UserActive bool `json:"Active" yaml:"Active,omitempty"`
|
||||
UserConfirmed bool `json:"Confirmed" yaml:"Confirmed,omitempty"`
|
||||
RoleAdmin bool `json:"Admin" yaml:"Admin,omitempty"`
|
||||
RoleGuest bool `json:"Guest" yaml:"Guest,omitempty"`
|
||||
RoleChild bool `json:"Child" yaml:"Child,omitempty"`
|
||||
RoleFamily bool `json:"Family" yaml:"Family,omitempty"`
|
||||
RoleFriend bool `json:"Friend" yaml:"Friend,omitempty"`
|
||||
IsArtist bool `json:"Artist" yaml:"Artist,omitempty"`
|
||||
IsSubject bool `json:"Subject" yaml:"Subject,omitempty"`
|
||||
CanEdit bool `json:"CanEdit" yaml:"CanEdit,omitempty"`
|
||||
CanComment bool `json:"CanComment" yaml:"CanComment,omitempty"`
|
||||
CanUpload bool `json:"CanUpload" yaml:"CanUpload,omitempty"`
|
||||
CanDownload bool `json:"CanDownload" yaml:"CanDownload,omitempty"`
|
||||
WebDAV bool `gorm:"column:webdav" json:"WebDAV" yaml:"WebDAV,omitempty"`
|
||||
ApiToken string `json:"ApiToken" yaml:"ApiToken,omitempty"`
|
||||
BirthYear int `json:"BirthYear" yaml:"BirthYear,omitempty"`
|
||||
BirthMonth int `json:"BirthMonth" yaml:"BirthMonth,omitempty"`
|
||||
BirthDay int `json:"BirthDay" yaml:"BirthDay,omitempty"`
|
||||
LoginAttempts int `json:"-" yaml:"-,omitempty"`
|
||||
LoginAt *time.Time `json:"-" yaml:"-"`
|
||||
CreatedAt time.Time `json:"CreatedAt" yaml:"-"`
|
||||
UpdatedAt time.Time `json:"UpdatedAt" yaml:"-"`
|
||||
DeletedAt *time.Time `sql:"index" json:"DeletedAt,omitempty" yaml:"-"`
|
||||
ID int `gorm:"primary_key" json:"ID" yaml:"-"`
|
||||
PersonUID string `gorm:"type:varbinary(42);unique_index;" json:"UID" yaml:"UID"`
|
||||
ParentUID string `gorm:"type:varbinary(42);" json:"ParentUID" yaml:"ParentUID,omitempty"`
|
||||
UserUUID string `gorm:"type:varbinary(42);index;" json:"UserUUID" yaml:"UserUUID,omitempty"`
|
||||
UserName string `gorm:"size:64;" json:"UserName" yaml:"UserName,omitempty"`
|
||||
UserLocale string `gorm:"size:64;" json:"UserLocale" yaml:"UserLocale,omitempty"`
|
||||
TimeZone string `gorm:"size:255;" json:"TimeZone" yaml:"TimeZone,omitempty"`
|
||||
PrimaryEmail string `gorm:"size:255;index;" json:"PrimaryEmail" yaml:"PrimaryEmail,omitempty"`
|
||||
BackupEmail string `gorm:"size:255;" json:"BackupEmail" yaml:"BackupEmail,omitempty"`
|
||||
DisplayName string `gorm:"size:255;" json:"DisplayName" yaml:"DisplayName,omitempty"`
|
||||
DisplayLocation string `gorm:"size:255;" json:"DisplayLocation" yaml:"DisplayLocation,omitempty"`
|
||||
DisplayBio string `gorm:"type:text;" json:"DisplayBio" yaml:"DisplayBio,omitempty"`
|
||||
NamePrefix string `gorm:"size:64;" json:"NamePrefix" yaml:"NamePrefix,omitempty"`
|
||||
GivenName string `gorm:"size:128;" json:"GivenName" yaml:"GivenName,omitempty"`
|
||||
FamilyName string `gorm:"size:128;" json:"FamilyName" yaml:"FamilyName,omitempty"`
|
||||
NameSuffix string `gorm:"size:64;" json:"NameSuffix" yaml:"NameSuffix,omitempty"`
|
||||
AvatarUID string `gorm:"type:varbinary(42);" json:"AvatarUID" yaml:"AvatarUID,omitempty"`
|
||||
AvatarURL string `gorm:"size:255;" json:"AvatarURL" yaml:"AvatarURL,omitempty"`
|
||||
FeedURL string `gorm:"size:255;" json:"FeedURL" yaml:"FeedURL,omitempty"`
|
||||
FeedType string `gorm:"size:64" json:"FeedType" yaml:"FeedType,omitempty"`
|
||||
FeedFollow bool `json:"FeedFollow" yaml:"FeedFollow,omitempty"`
|
||||
BlogURL string `gorm:"size:255;" json:"BlogURL" yaml:"BlogURL,omitempty"`
|
||||
BlogType string `gorm:"size:64;" json:"BlogType" yaml:"BlogType,omitempty"`
|
||||
BlogFollow bool `json:"BlogFollow" yaml:"BlogFollow,omitempty"`
|
||||
CompanyURL string `gorm:"size:255;" json:"CompanyURL" yaml:"CompanyURL,omitempty"`
|
||||
CompanyName string `gorm:"size:128;" json:"CompanyName" yaml:"CompanyName,omitempty"`
|
||||
CompanyPhone string `gorm:"size:255;" json:"CompanyPhone" yaml:"CompanyPhone,omitempty"`
|
||||
PrimaryPhone string `gorm:"size:255;" json:"PrimaryPhone" yaml:"PrimaryPhone,omitempty"`
|
||||
DepartmentName string `gorm:"size:255;" json:"DepartmentName" yaml:"DepartmentName,omitempty"`
|
||||
JobTitle string `gorm:"size:255;" json:"JobTitle" yaml:"JobTitle,omitempty"`
|
||||
AddressLat float32 `gorm:"type:FLOAT;index;" json:"AddressLat" yaml:"AddressLat,omitempty"`
|
||||
AddressLng float32 `gorm:"type:FLOAT;index;" json:"AddressLng" yaml:"AddressLng,omitempty"`
|
||||
AddressLine1 string `gorm:"size:255;" json:"AddressLine1" yaml:"AddressLine1,omitempty"`
|
||||
AddressLine2 string `gorm:"size:255;" json:"AddressLine2" yaml:"AddressLine2,omitempty"`
|
||||
AddressZip string `gorm:"size:255;" json:"AddressZip" yaml:"AddressZip,omitempty"`
|
||||
AddressCity string `gorm:"size:255;" json:"AddressCity" yaml:"AddressCity,omitempty"`
|
||||
AddressState string `gorm:"size:255;" json:"AddressState" yaml:"AddressState,omitempty"`
|
||||
AddressCountry string `gorm:"type:varbinary(2);default:'zz'" json:"AddressCountry" yaml:"AddressCountry,omitempty"`
|
||||
BirthYear int `json:"BirthYear" yaml:"BirthYear,omitempty"`
|
||||
BirthMonth int `json:"BirthMonth" yaml:"BirthMonth,omitempty"`
|
||||
BirthDay int `json:"BirthDay" yaml:"BirthDay,omitempty"`
|
||||
TermsAccepted bool `json:"TermsAccepted" yaml:"TermsAccepted,omitempty"`
|
||||
IsActive bool `json:"IsActive" yaml:"IsActive,omitempty"`
|
||||
IsConfirmed bool `json:"IsConfirmed" yaml:"IsConfirmed,omitempty"`
|
||||
IsPro bool `json:"IsPro" yaml:"IsPro,omitempty"`
|
||||
IsSponsor bool `json:"IsSponsor" yaml:"IsSponsor,omitempty"`
|
||||
IsContributor bool `json:"IsContributor" yaml:"IsContributor,omitempty"`
|
||||
IsArtist bool `json:"IsArtist" yaml:"IsArtist,omitempty"`
|
||||
IsSubject bool `json:"IsSubject" yaml:"IsSubject,omitempty"`
|
||||
RoleAdmin bool `json:"RoleAdmin" yaml:"RoleAdmin,omitempty"`
|
||||
RoleGuest bool `json:"RoleGuest" yaml:"RoleGuest,omitempty"`
|
||||
RoleChild bool `json:"RoleChild" yaml:"RoleChild,omitempty"`
|
||||
RoleFamily bool `json:"RoleFamily" yaml:"RoleFamily,omitempty"`
|
||||
RoleFriend bool `json:"RoleFriend" yaml:"RoleFriend,omitempty"`
|
||||
CanEdit bool `json:"CanEdit" yaml:"CanEdit,omitempty"`
|
||||
CanDelete bool `json:"CanDelete" yaml:"CanDelete,omitempty"`
|
||||
CanIndex bool `json:"CanIndex" yaml:"CanIndex,omitempty"`
|
||||
CanShare bool `json:"CanShare" yaml:"CanShare,omitempty"`
|
||||
CanComment bool `json:"CanComment" yaml:"CanComment,omitempty"`
|
||||
CanUpload bool `json:"CanUpload" yaml:"CanUpload,omitempty"`
|
||||
CanDownload bool `json:"CanDownload" yaml:"CanDownload,omitempty"`
|
||||
HideLabels bool `json:"HideLabels" yaml:"HideLabels,omitempty"`
|
||||
HidePlaces bool `json:"HidePlaces" yaml:"HidePlaces,omitempty"`
|
||||
HidePeople bool `json:"HidePeople" yaml:"HidePeople,omitempty"`
|
||||
HidePrivate bool `json:"HidePrivate" yaml:"HidePrivate,omitempty"`
|
||||
HideLibrary bool `json:"HideLibrary" yaml:"HideLibrary,omitempty"`
|
||||
HideSettings bool `json:"HideSettings" yaml:"HideSettings,omitempty"`
|
||||
WebDAV bool `gorm:"column:webdav" json:"WebDAV" yaml:"WebDAV,omitempty"`
|
||||
StoragePath string `gorm:"column:storage_path;size:255;" json:"StoragePath" yaml:"StoragePath,omitempty"`
|
||||
ApiToken string `gorm:"column:api_token;size:255;" json:"ApiToken" yaml:"ApiToken,omitempty"`
|
||||
ApiSecret string `gorm:"column:api_secret;size:255;" json:"-" yaml:"-"`
|
||||
AmazonID string `gorm:"column:amazon_id;size:255;" json:"AmazonID" yaml:"AmazonID,omitempty"`
|
||||
AppleID string `gorm:"column:apple_id;size:255;" json:"AppleID" yaml:"AppleID,omitempty"`
|
||||
EyeEmID string `gorm:"column:eyeem_id;size:255;" json:"EyeEmID" yaml:"EyeEmID,omitempty"`
|
||||
FacebookID string `gorm:"column:facebook_id;size:255;" json:"FacebookID" yaml:"FacebookID,omitempty"`
|
||||
FlickrID string `gorm:"column:flickr_id;size:255;" json:"FlickrID" yaml:"FlickrID,omitempty"`
|
||||
GitHubID string `gorm:"column:github_id;size:255;" json:"GitHubID" yaml:"GitHubID,omitempty"`
|
||||
GitLabID string `gorm:"column:gitlab_id;size:255;" json:"GitLabID" yaml:"GitLabID,omitempty"`
|
||||
GoogleID string `gorm:"column:google_id;size:255;" json:"GoogleID" yaml:"GoogleID,omitempty"`
|
||||
InstagramID string `gorm:"column:instagram_id;size:255;" json:"InstagramID" yaml:"InstagramID,omitempty"`
|
||||
LinkedinID string `gorm:"column:linkedin_id;size:255;" json:"LinkedinID" yaml:"LinkedinID,omitempty"`
|
||||
MastodonID string `gorm:"column:mastodon_id;size:255;" json:"MastodonID" yaml:"MastodonID,omitempty"`
|
||||
NextcloudID string `gorm:"column:nextcloud_id;size:255;" json:"NextcloudID" yaml:"NextcloudID,omitempty"`
|
||||
TelegramID string `gorm:"column:telegram_id;size:255;" json:"TelegramID" yaml:"TelegramID,omitempty"`
|
||||
TwitterID string `gorm:"column:twitter_id;size:255;" json:"TwitterID" yaml:"TwitterID,omitempty"`
|
||||
WhatsAppID string `gorm:"column:whatsapp_id;size:255;" json:"WhatsAppID" yaml:"WhatsAppID,omitempty"`
|
||||
YouTubeID string `gorm:"column:youtube_id;size:255;" json:"YouTubeID" yaml:"YouTubeID,omitempty"`
|
||||
UserNotes string `gorm:"type:text;" json:"UserNotes" yaml:"UserNotes,omitempty"`
|
||||
LoginAttempts int `json:"-" yaml:"-,omitempty"`
|
||||
LoginAt *time.Time `json:"-" yaml:"-"`
|
||||
CreatedAt time.Time `json:"CreatedAt" yaml:"-"`
|
||||
UpdatedAt time.Time `json:"UpdatedAt" yaml:"-"`
|
||||
DeletedAt *time.Time `sql:"index" json:"DeletedAt,omitempty" yaml:"-"`
|
||||
}
|
||||
|
||||
// TableName the database table name.
|
||||
func (Person) TableName() string {
|
||||
return "people"
|
||||
}
|
||||
|
||||
// Default admin user.
|
||||
var Admin = Person{
|
||||
ID: 1,
|
||||
UserName: "admin",
|
||||
DisplayName: "Admin",
|
||||
RoleAdmin: true,
|
||||
UserActive: true,
|
||||
UserConfirmed: true,
|
||||
ID: 1,
|
||||
UserName: "admin",
|
||||
DisplayName: "Admin",
|
||||
RoleAdmin: true,
|
||||
IsActive: true,
|
||||
IsConfirmed: true,
|
||||
}
|
||||
|
||||
// Anonymous, public user without own account.
|
||||
var UnknownPerson = Person{
|
||||
ID: -1,
|
||||
PersonUID: "u000000000000001",
|
||||
UserName: "",
|
||||
DisplayName: "Anonymous",
|
||||
RoleAdmin: false,
|
||||
RoleGuest: false,
|
||||
UserActive: false,
|
||||
UserConfirmed: false,
|
||||
ID: -1,
|
||||
PersonUID: "u000000000000001",
|
||||
UserName: "",
|
||||
DisplayName: "Anonymous",
|
||||
RoleAdmin: false,
|
||||
RoleGuest: false,
|
||||
IsActive: false,
|
||||
IsConfirmed: false,
|
||||
}
|
||||
|
||||
// Guest user without own account for link sharing.
|
||||
var Guest = Person{
|
||||
ID: -2,
|
||||
PersonUID: "u000000000000002",
|
||||
UserName: "",
|
||||
DisplayName: "Guest",
|
||||
RoleAdmin: false,
|
||||
RoleGuest: true,
|
||||
UserActive: false,
|
||||
UserConfirmed: false,
|
||||
ID: -2,
|
||||
PersonUID: "u000000000000002",
|
||||
UserName: "",
|
||||
DisplayName: "Guest",
|
||||
RoleAdmin: false,
|
||||
RoleGuest: true,
|
||||
IsActive: false,
|
||||
IsConfirmed: false,
|
||||
}
|
||||
|
||||
// CreateDefaultUsers initializes the database with default user accounts.
|
||||
|
|
|
@ -24,8 +24,10 @@ type Location struct {
|
|||
|
||||
const ApiName = "photoprism places"
|
||||
|
||||
var ReverseLookupURL = "https://places.photoprism.org/v1/location/%s"
|
||||
var client = &http.Client{Timeout: 60 * time.Second} // TODO: Change timeout if needed
|
||||
var Key = ""
|
||||
var UserAgent = "PhotoPrism/DEVELOP"
|
||||
var ReverseLookupURL = "https://places.photoprism.pro/v1/location/%s?key=%s"
|
||||
var client = &http.Client{Timeout: 60 * time.Second}
|
||||
|
||||
func NewLocation(id string, lat, lng float64, name, category string, place Place, cached bool) *Location {
|
||||
result := &Location{
|
||||
|
@ -63,7 +65,7 @@ func FindLocation(id string) (result Location, err error) {
|
|||
}
|
||||
}
|
||||
|
||||
url := fmt.Sprintf(ReverseLookupURL, id)
|
||||
url := fmt.Sprintf(ReverseLookupURL, id, Key)
|
||||
|
||||
log.Debugf("api: sending request to %s (%s)", url, ApiName)
|
||||
|
||||
|
@ -74,6 +76,8 @@ func FindLocation(id string) (result Location, err error) {
|
|||
return result, err
|
||||
}
|
||||
|
||||
req.Header.Set("User-Agent", UserAgent)
|
||||
|
||||
var r *http.Response
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
|
|
Loading…
Reference in a new issue