2022-10-02 11:38:30 +02:00
|
|
|
package entity
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/photoprism/photoprism/internal/event"
|
|
|
|
"github.com/photoprism/photoprism/pkg/clean"
|
|
|
|
"github.com/photoprism/photoprism/pkg/rnd"
|
|
|
|
)
|
|
|
|
|
|
|
|
const PermDefault uint = 0
|
|
|
|
|
|
|
|
const (
|
|
|
|
PermNone uint = 1 << iota
|
|
|
|
PermView
|
|
|
|
PermReact
|
|
|
|
PermComment
|
|
|
|
PermUpload
|
|
|
|
PermEdit
|
|
|
|
PermShare
|
|
|
|
PermAll
|
|
|
|
)
|
|
|
|
|
|
|
|
// SharePrefix for RefID.
|
|
|
|
const (
|
|
|
|
SharePrefix = "share"
|
|
|
|
)
|
|
|
|
|
2022-10-04 00:54:39 +02:00
|
|
|
// UserShares represents shared content.
|
|
|
|
type UserShares []UserShare
|
2022-10-02 11:38:30 +02:00
|
|
|
|
|
|
|
// UIDs returns shared UIDs.
|
2022-10-04 00:54:39 +02:00
|
|
|
func (m UserShares) UIDs() UIDs {
|
2022-10-02 11:38:30 +02:00
|
|
|
result := make(UIDs, len(m))
|
|
|
|
|
|
|
|
for i, share := range m {
|
|
|
|
result[i] = share.ShareUID
|
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
// Empty checks if there are no shares.
|
2022-10-04 00:54:39 +02:00
|
|
|
func (m UserShares) Empty() bool {
|
2022-10-02 11:38:30 +02:00
|
|
|
return m == nil || len(m) == 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// Contains checks the uid is shared.
|
2022-10-04 00:54:39 +02:00
|
|
|
func (m UserShares) Contains(uid string) bool {
|
2022-10-02 11:38:30 +02:00
|
|
|
if len(m) == 0 {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, share := range m {
|
|
|
|
if share.ShareUID == uid {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2022-10-04 00:54:39 +02:00
|
|
|
// UserShare represents content shared with a user.
|
|
|
|
type UserShare struct {
|
2022-10-02 11:38:30 +02:00
|
|
|
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"`
|
|
|
|
ExpiresAt *time.Time `sql:"index" json:"ExpiresAt,omitempty" yaml:"ExpiresAt,omitempty"`
|
|
|
|
Comment string `gorm:"size:512;" json:"Comment,omitempty" yaml:"Comment,omitempty"`
|
|
|
|
Perm uint `json:"Perm,omitempty" yaml:"Perm,omitempty"`
|
|
|
|
RefID string `gorm:"type:VARBINARY(16);" json:"-" yaml:"-"`
|
|
|
|
CreatedAt time.Time `json:"CreatedAt" yaml:"-"`
|
|
|
|
UpdatedAt time.Time `json:"UpdatedAt" yaml:"-"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// TableName returns the entity table name.
|
2022-10-04 00:54:39 +02:00
|
|
|
func (UserShare) TableName() string {
|
2022-10-02 22:09:02 +02:00
|
|
|
return "auth_users_shares"
|
2022-10-02 11:38:30 +02:00
|
|
|
}
|
|
|
|
|
2022-10-04 00:54:39 +02:00
|
|
|
// NewUserShare creates a new entity model.
|
|
|
|
func NewUserShare(userUID, shareUid string, perm uint, expires *time.Time) *UserShare {
|
|
|
|
result := &UserShare{
|
2022-10-02 11:38:30 +02:00
|
|
|
UserUID: userUID,
|
|
|
|
ShareUID: shareUid,
|
|
|
|
Perm: perm,
|
|
|
|
RefID: rnd.RefID(SharePrefix),
|
|
|
|
CreatedAt: TimeStamp(),
|
|
|
|
UpdatedAt: TimeStamp(),
|
|
|
|
ExpiresAt: expires,
|
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2022-10-04 00:54:39 +02:00
|
|
|
// FindUserShare fetches the matching record or returns null if it was not found.
|
|
|
|
func FindUserShare(find UserShare) *UserShare {
|
2022-10-02 11:38:30 +02:00
|
|
|
if !find.HasID() {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-10-04 00:54:39 +02:00
|
|
|
m := &UserShare{}
|
2022-10-02 11:38:30 +02:00
|
|
|
|
|
|
|
// Find matching record.
|
|
|
|
if UnscopedDb().First(m, "user_uid = ? AND share_uid = ?", find.UserUID, find.ShareUID).RecordNotFound() {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return m
|
|
|
|
}
|
|
|
|
|
2022-10-04 00:54:39 +02:00
|
|
|
// FindUserShares finds all shares to which the user has access.
|
|
|
|
func FindUserShares(userUid string) UserShares {
|
|
|
|
found := UserShares{}
|
2022-10-02 11:38:30 +02:00
|
|
|
|
|
|
|
if rnd.InvalidUID(userUid, UserUID) {
|
|
|
|
return found
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find matching record.
|
|
|
|
if err := UnscopedDb().Find(&found, "user_uid = ? AND (expires_at IS NULL OR expires_at > ?)", userUid, TimeStamp()).Error; err != nil {
|
|
|
|
event.AuditWarn([]string{"user %s", "find shares", "%s"}, clean.Log(userUid), err)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return found
|
|
|
|
}
|
|
|
|
|
|
|
|
// HasID tests if the entity has a valid uid.
|
2022-10-04 00:54:39 +02:00
|
|
|
func (m *UserShare) HasID() bool {
|
2022-10-02 11:38:30 +02:00
|
|
|
return rnd.IsUID(m.UserUID, UserUID) && rnd.IsUID(m.ShareUID, 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create inserts a new record into the database.
|
2022-10-04 00:54:39 +02:00
|
|
|
func (m *UserShare) Create() error {
|
2022-10-02 11:38:30 +02:00
|
|
|
return Db().Create(m).Error
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save updates the record in the database or inserts a new record if it does not already exist.
|
2022-10-04 00:54:39 +02:00
|
|
|
func (m *UserShare) Save() error {
|
2022-10-02 11:38:30 +02:00
|
|
|
return Db().Save(m).Error
|
|
|
|
}
|
|
|
|
|
|
|
|
// Updates changes multiple record values.
|
2022-10-04 00:54:39 +02:00
|
|
|
func (m *UserShare) Updates(values interface{}) error {
|
2022-10-02 11:38:30 +02:00
|
|
|
return UnscopedDb().Model(m).Updates(values).Error
|
|
|
|
}
|
|
|
|
|
|
|
|
// UpdateLink updates the share data using the Link provided.
|
2022-10-04 00:54:39 +02:00
|
|
|
func (m *UserShare) UpdateLink(link Link) error {
|
2022-10-02 11:38:30 +02:00
|
|
|
if m.ShareUID != link.ShareUID {
|
|
|
|
return fmt.Errorf("shared uid does not match")
|
|
|
|
}
|
|
|
|
|
|
|
|
m.LinkUID = link.LinkUID
|
|
|
|
m.Comment = link.Comment
|
|
|
|
m.Perm = link.Perm
|
|
|
|
m.UpdatedAt = TimeStamp()
|
|
|
|
m.ExpiresAt = link.ExpiresAt()
|
|
|
|
|
|
|
|
values := Values{
|
|
|
|
"link_uid": m.LinkUID,
|
|
|
|
"expires_at": m.ExpiresAt,
|
|
|
|
"comment": m.Comment,
|
|
|
|
"perm": m.Perm,
|
|
|
|
"updated_at": m.UpdatedAt}
|
|
|
|
|
|
|
|
return m.Updates(values)
|
|
|
|
}
|