Signed-off-by: Michael Mayer <michael@photoprism.app>
This commit is contained in:
parent
b390e34b78
commit
693108fd53
7 changed files with 71 additions and 54 deletions
|
@ -62,6 +62,7 @@ type User struct {
|
|||
BornAt *time.Time `sql:"index" json:"BornAt,omitempty" yaml:"BornAt,omitempty"`
|
||||
UserDetails *UserDetails `gorm:"PRELOAD:true;foreignkey:UserUID;association_foreignkey:UserUID;" json:"Details,omitempty" yaml:"Details,omitempty"`
|
||||
UserSettings *UserSettings `gorm:"PRELOAD:true;foreignkey:UserUID;association_foreignkey:UserUID;" json:"Settings,omitempty" yaml:"Settings,omitempty"`
|
||||
UserShares UserShares `gorm:"-" json:"Shares,omitempty" yaml:"Shares,omitempty"`
|
||||
ResetToken string `gorm:"type:VARBINARY(64);" json:"-" yaml:"-"`
|
||||
PreviewToken string `gorm:"type:VARBINARY(64);column:preview_token;" json:"-" yaml:"-"`
|
||||
DownloadToken string `gorm:"type:VARBINARY(64);column:download_token;" json:"-" yaml:"-"`
|
||||
|
@ -71,7 +72,6 @@ type User struct {
|
|||
CreatedAt time.Time `json:"CreatedAt" yaml:"-"`
|
||||
UpdatedAt time.Time `json:"UpdatedAt" yaml:"-"`
|
||||
DeletedAt *time.Time `sql:"index" json:"DeletedAt,omitempty" yaml:"-"`
|
||||
Shares Shares `gorm:"-" json:"Shares,omitempty" yaml:"Shares,omitempty"`
|
||||
}
|
||||
|
||||
// TableName returns the entity table name.
|
||||
|
@ -635,7 +635,7 @@ func (m *User) SetFormValues(frm form.User) *User {
|
|||
|
||||
// RefreshShares updates the list of shares.
|
||||
func (m *User) RefreshShares() *User {
|
||||
m.Shares = FindShares(m.UID())
|
||||
m.UserShares = FindUserShares(m.UID())
|
||||
return m
|
||||
}
|
||||
|
||||
|
@ -645,7 +645,7 @@ func (m *User) NoShares() bool {
|
|||
return true
|
||||
}
|
||||
|
||||
return m.Shares.Empty()
|
||||
return m.UserShares.Empty()
|
||||
}
|
||||
|
||||
// HasShares checks if the user has any shares.
|
||||
|
@ -659,16 +659,16 @@ func (m *User) HasShare(uid string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
return m.Shares.Contains(uid)
|
||||
return m.UserShares.Contains(uid)
|
||||
}
|
||||
|
||||
// SharedUIDs returns shared entity UIDs.
|
||||
func (m *User) SharedUIDs() UIDs {
|
||||
if m.IsRegistered() && m.Shares.Empty() {
|
||||
if m.IsRegistered() && m.UserShares.Empty() {
|
||||
m.RefreshShares()
|
||||
}
|
||||
|
||||
return m.Shares.UIDs()
|
||||
return m.UserShares.UIDs()
|
||||
}
|
||||
|
||||
// RedeemToken updates shared entity UIDs using the specified token.
|
||||
|
@ -687,8 +687,8 @@ func (m *User) RedeemToken(token string) (n int) {
|
|||
|
||||
// Find shares.
|
||||
for _, link := range links {
|
||||
if found := FindShare(Share{UserUID: m.UID(), ShareUID: link.ShareUID}); found == nil {
|
||||
share := NewShare(m.UID(), link.ShareUID, link.Perm, link.ExpiresAt())
|
||||
if found := FindUserShare(UserShare{UserUID: m.UID(), ShareUID: link.ShareUID}); found == nil {
|
||||
share := NewUserShare(m.UID(), link.ShareUID, link.Perm, link.ExpiresAt())
|
||||
share.LinkUID = link.LinkUID
|
||||
share.Comment = link.Comment
|
||||
|
||||
|
|
|
@ -27,11 +27,11 @@ const (
|
|||
SharePrefix = "share"
|
||||
)
|
||||
|
||||
// Shares represents shared content.
|
||||
type Shares []Share
|
||||
// UserShares represents shared content.
|
||||
type UserShares []UserShare
|
||||
|
||||
// UIDs returns shared UIDs.
|
||||
func (m Shares) UIDs() UIDs {
|
||||
func (m UserShares) UIDs() UIDs {
|
||||
result := make(UIDs, len(m))
|
||||
|
||||
for i, share := range m {
|
||||
|
@ -42,12 +42,12 @@ func (m Shares) UIDs() UIDs {
|
|||
}
|
||||
|
||||
// Empty checks if there are no shares.
|
||||
func (m Shares) Empty() bool {
|
||||
func (m UserShares) Empty() bool {
|
||||
return m == nil || len(m) == 0
|
||||
}
|
||||
|
||||
// Contains checks the uid is shared.
|
||||
func (m Shares) Contains(uid string) bool {
|
||||
func (m UserShares) Contains(uid string) bool {
|
||||
if len(m) == 0 {
|
||||
return false
|
||||
}
|
||||
|
@ -61,8 +61,8 @@ func (m Shares) Contains(uid string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// Share represents content shared with a user.
|
||||
type Share struct {
|
||||
// UserShare represents content shared with a user.
|
||||
type UserShare struct {
|
||||
UserUID string `gorm:"type:VARBINARY(42);primary_key;auto_increment:false;" json:"-" yaml:"UserUID"`
|
||||
ShareUID string `gorm:"type:VARBINARY(42);primary_key;index;" json:"ShareUID" yaml:"ShareUID"`
|
||||
LinkUID string `gorm:"type:VARBINARY(42);" json:"LinkUID,omitempty" yaml:"LinkUID,omitempty"`
|
||||
|
@ -75,13 +75,13 @@ type Share struct {
|
|||
}
|
||||
|
||||
// TableName returns the entity table name.
|
||||
func (Share) TableName() string {
|
||||
func (UserShare) TableName() string {
|
||||
return "auth_users_shares"
|
||||
}
|
||||
|
||||
// NewShare creates a new entity model.
|
||||
func NewShare(userUID, shareUid string, perm uint, expires *time.Time) *Share {
|
||||
result := &Share{
|
||||
// NewUserShare creates a new entity model.
|
||||
func NewUserShare(userUID, shareUid string, perm uint, expires *time.Time) *UserShare {
|
||||
result := &UserShare{
|
||||
UserUID: userUID,
|
||||
ShareUID: shareUid,
|
||||
Perm: perm,
|
||||
|
@ -94,13 +94,13 @@ func NewShare(userUID, shareUid string, perm uint, expires *time.Time) *Share {
|
|||
return result
|
||||
}
|
||||
|
||||
// FindShare fetches the matching record or returns null if it was not found.
|
||||
func FindShare(find Share) *Share {
|
||||
// FindUserShare fetches the matching record or returns null if it was not found.
|
||||
func FindUserShare(find UserShare) *UserShare {
|
||||
if !find.HasID() {
|
||||
return nil
|
||||
}
|
||||
|
||||
m := &Share{}
|
||||
m := &UserShare{}
|
||||
|
||||
// Find matching record.
|
||||
if UnscopedDb().First(m, "user_uid = ? AND share_uid = ?", find.UserUID, find.ShareUID).RecordNotFound() {
|
||||
|
@ -110,9 +110,9 @@ func FindShare(find Share) *Share {
|
|||
return m
|
||||
}
|
||||
|
||||
// FindShares finds all shares to which the user has access.
|
||||
func FindShares(userUid string) Shares {
|
||||
found := Shares{}
|
||||
// FindUserShares finds all shares to which the user has access.
|
||||
func FindUserShares(userUid string) UserShares {
|
||||
found := UserShares{}
|
||||
|
||||
if rnd.InvalidUID(userUid, UserUID) {
|
||||
return found
|
||||
|
@ -128,27 +128,27 @@ func FindShares(userUid string) Shares {
|
|||
}
|
||||
|
||||
// HasID tests if the entity has a valid uid.
|
||||
func (m *Share) HasID() bool {
|
||||
func (m *UserShare) HasID() bool {
|
||||
return rnd.IsUID(m.UserUID, UserUID) && rnd.IsUID(m.ShareUID, 0)
|
||||
}
|
||||
|
||||
// Create inserts a new record into the database.
|
||||
func (m *Share) Create() error {
|
||||
func (m *UserShare) Create() error {
|
||||
return Db().Create(m).Error
|
||||
}
|
||||
|
||||
// Save updates the record in the database or inserts a new record if it does not already exist.
|
||||
func (m *Share) Save() error {
|
||||
func (m *UserShare) Save() error {
|
||||
return Db().Save(m).Error
|
||||
}
|
||||
|
||||
// Updates changes multiple record values.
|
||||
func (m *Share) Updates(values interface{}) error {
|
||||
func (m *UserShare) Updates(values interface{}) error {
|
||||
return UnscopedDb().Model(m).Updates(values).Error
|
||||
}
|
||||
|
||||
// UpdateLink updates the share data using the Link provided.
|
||||
func (m *Share) UpdateLink(link Link) error {
|
||||
func (m *UserShare) UpdateLink(link Link) error {
|
||||
if m.ShareUID != link.ShareUID {
|
||||
return fmt.Errorf("shared uid does not match")
|
||||
}
|
|
@ -4,28 +4,28 @@ import (
|
|||
"github.com/photoprism/photoprism/pkg/rnd"
|
||||
)
|
||||
|
||||
type ShareMap map[string]Share
|
||||
type UserShareMap map[string]UserShare
|
||||
|
||||
// Get returns a fixture for use in tests.
|
||||
func (m ShareMap) Get(name string) Share {
|
||||
func (m UserShareMap) Get(name string) UserShare {
|
||||
if result, ok := m[name]; ok {
|
||||
return result
|
||||
}
|
||||
|
||||
return Share{}
|
||||
return UserShare{}
|
||||
}
|
||||
|
||||
// Pointer returns a fixture pointer for use in tests.
|
||||
func (m ShareMap) Pointer(name string) *Share {
|
||||
func (m UserShareMap) Pointer(name string) *UserShare {
|
||||
if result, ok := m[name]; ok {
|
||||
return &result
|
||||
}
|
||||
|
||||
return &Share{}
|
||||
return &UserShare{}
|
||||
}
|
||||
|
||||
// ShareFixtures specifies fixtures for use in tests.
|
||||
var ShareFixtures = ShareMap{
|
||||
// UserShareFixtures specifies fixtures for use in tests.
|
||||
var UserShareFixtures = UserShareMap{
|
||||
"AliceAlbum": {
|
||||
UserUID: "uqxetse3cy5eo9z2",
|
||||
ShareUID: "at9lxuqxpogaaba9",
|
||||
|
@ -38,9 +38,9 @@ var ShareFixtures = ShareMap{
|
|||
},
|
||||
}
|
||||
|
||||
// CreateShareFixtures creates the fixtures specified above.
|
||||
func CreateShareFixtures() {
|
||||
for _, entity := range ShareFixtures {
|
||||
// CreateUserShareFixtures creates the fixtures specified above.
|
||||
func CreateUserShareFixtures() {
|
||||
for _, entity := range UserShareFixtures {
|
||||
Db().Create(&entity)
|
||||
}
|
||||
}
|
|
@ -9,9 +9,9 @@ import (
|
|||
"github.com/photoprism/photoprism/pkg/rnd"
|
||||
)
|
||||
|
||||
func TestNewShare(t *testing.T) {
|
||||
func TestNewUserShare(t *testing.T) {
|
||||
expires := TimeStamp().Add(time.Hour * 48)
|
||||
m := NewShare(Admin.UID(), AlbumFixtures.Get("berlin-2019").AlbumUID, PermReact, &expires)
|
||||
m := NewUserShare(Admin.UID(), AlbumFixtures.Get("berlin-2019").AlbumUID, PermReact, &expires)
|
||||
|
||||
assert.True(t, m.HasID())
|
||||
assert.True(t, rnd.IsRefID(m.RefID))
|
||||
|
@ -35,11 +35,11 @@ func TestPerm(t *testing.T) {
|
|||
assert.Equal(t, uint(128), PermAll)
|
||||
}
|
||||
|
||||
func TestFindShare(t *testing.T) {
|
||||
func TestFindUserShare(t *testing.T) {
|
||||
t.Run("AliceAlbum", func(t *testing.T) {
|
||||
m := FindShare(Share{UserUID: "uqxetse3cy5eo9z2", ShareUID: "at9lxuqxpogaaba9"})
|
||||
m := FindUserShare(UserShare{UserUID: "uqxetse3cy5eo9z2", ShareUID: "at9lxuqxpogaaba9"})
|
||||
|
||||
expected := ShareFixtures.Get("AliceAlbum")
|
||||
expected := UserShareFixtures.Get("AliceAlbum")
|
||||
|
||||
assert.NotNil(t, m)
|
||||
assert.True(t, m.HasID())
|
||||
|
@ -55,13 +55,13 @@ func TestFindShare(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestFindShares(t *testing.T) {
|
||||
found := FindShares(UserFixtures.Pointer("alice").UID())
|
||||
func TestFindUserShares(t *testing.T) {
|
||||
found := FindUserShares(UserFixtures.Pointer("alice").UID())
|
||||
assert.NotNil(t, found)
|
||||
assert.Len(t, found, 1)
|
||||
|
||||
m := found[0]
|
||||
expected := ShareFixtures.Get("AliceAlbum")
|
||||
expected := UserShareFixtures.Get("AliceAlbum")
|
||||
|
||||
assert.NotNil(t, m)
|
||||
assert.True(t, m.HasID())
|
|
@ -48,7 +48,7 @@ var Entities = Tables{
|
|||
Face{}.TableName(): &Face{},
|
||||
Marker{}.TableName(): &Marker{},
|
||||
Reaction{}.TableName(): &Reaction{},
|
||||
Share{}.TableName(): &Share{},
|
||||
UserShare{}.TableName(): &UserShare{},
|
||||
}
|
||||
|
||||
// WaitForMigration waits for the database migration to be successful.
|
||||
|
|
|
@ -31,5 +31,5 @@ func CreateTestFixtures() {
|
|||
CreateSessionFixtures()
|
||||
CreateReactionFixtures()
|
||||
CreatePasswordFixtures()
|
||||
CreateShareFixtures()
|
||||
CreateUserShareFixtures()
|
||||
}
|
||||
|
|
|
@ -4,17 +4,18 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/event"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/event"
|
||||
"github.com/photoprism/photoprism/pkg/clean"
|
||||
"github.com/photoprism/photoprism/pkg/rnd"
|
||||
"github.com/photoprism/photoprism/pkg/txt"
|
||||
)
|
||||
|
||||
// LinkPrefix for RefID.
|
||||
const (
|
||||
LinkUID = byte('s')
|
||||
LinkUID = byte('s')
|
||||
LinkPrefix = "link"
|
||||
)
|
||||
|
||||
type Links []Link
|
||||
|
@ -45,7 +46,7 @@ func (Link) TableName() string {
|
|||
// BeforeCreate creates a random UID if needed before inserting a new row to the database.
|
||||
func (m *Link) BeforeCreate(scope *gorm.Scope) error {
|
||||
if rnd.InvalidRefID(m.RefID) {
|
||||
m.RefID = rnd.RefID(SessionPrefix)
|
||||
m.RefID = rnd.RefID(LinkPrefix)
|
||||
Log("link", "set ref id", scope.SetColumn("RefID", m.RefID))
|
||||
}
|
||||
|
||||
|
@ -165,6 +166,13 @@ func (m *Link) Save() error {
|
|||
func (m *Link) Delete() error {
|
||||
if m.LinkToken == "" {
|
||||
return fmt.Errorf("empty link token")
|
||||
} else if m.LinkUID == "" {
|
||||
return fmt.Errorf("empty link uid")
|
||||
}
|
||||
|
||||
// Remove related user shares.
|
||||
if err := UnscopedDb().Delete(UserShare{}, "link_uid = ?", m.LinkUID).Error; err != nil {
|
||||
event.AuditErr([]string{"link %s", "failed to remove related user shares", "%s"}, clean.Log(m.RefID), err)
|
||||
}
|
||||
|
||||
return Db().Delete(m).Error
|
||||
|
@ -172,6 +180,15 @@ func (m *Link) Delete() error {
|
|||
|
||||
// DeleteShareLinks removes all links that match the shared UID.
|
||||
func DeleteShareLinks(shareUid string) error {
|
||||
if shareUid == "" {
|
||||
return fmt.Errorf("empty share uid")
|
||||
}
|
||||
|
||||
// Remove related user shares.
|
||||
if err := UnscopedDb().Delete(UserShare{}, "share_uid = ?", shareUid).Error; err != nil {
|
||||
event.AuditErr([]string{"share %s", "failed to remove related user shares", "%s"}, clean.Log(shareUid), err)
|
||||
}
|
||||
|
||||
return Db().Delete(&Link{}, "share_uid = ?", shareUid).Error
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue