You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
360 lines
7.5 KiB
360 lines
7.5 KiB
package model |
|
|
|
import ( |
|
"errors" |
|
"fmt" |
|
"sort" |
|
"strings" |
|
|
|
"go-common/library/time" |
|
) |
|
|
|
const ( |
|
// default name of folder |
|
InitFolderName = "默认收藏夹" |
|
// state |
|
StateNormal = int8(0) |
|
StateIsDel = int8(1) |
|
// attr bit bit from left |
|
AttrBitPublic = uint(0) |
|
AttrBitDefault = uint(1) |
|
AttrBitAudit = uint(2) |
|
AttrBitAdminDelete = uint(3) |
|
AttrBitName = uint(4) |
|
AttrBitDesc = uint(5) |
|
AttrBitCover = uint(6) |
|
AttrBitSensitive = uint(7) |
|
|
|
AttrIsPublic = int32(0) // 公开 |
|
AttrIsDefault = int32(0) // 默认 |
|
// foler attr |
|
AttrBitPrivate = int32(1) |
|
AttrBitNoDefault = int32(1) << AttrBitDefault |
|
AttrBitNeedAudit = int32(1) << AttrBitAudit |
|
AttrBitHitSensitive = int32(1) << AttrBitSensitive |
|
|
|
AttrDefaultPublic = 0 // binary 0 / int 0 |
|
AttrDefaultNoPublic = AttrBitPrivate // binary 01 / int 1 |
|
AttrNormalPublic = AttrBitNoDefault // binary 10 / int 2 |
|
AttrNormalNoPublic = AttrBitNoDefault | AttrBitPrivate // binary 11 / int 3 |
|
// limit |
|
DefaultFolderLimit = 50000 |
|
NormalFolderLimit = 999 |
|
// cache |
|
CacheNotFound = -1 |
|
// max type |
|
TypeMax = 20 |
|
// sort field |
|
SortPubtime = "pubtime" |
|
SortMtime = "mtime" |
|
SortView = "view" |
|
) |
|
|
|
func (r *Resource) ResourceID() int64 { |
|
return r.Oid*100 + int64(r.Typ) |
|
} |
|
|
|
func IsMediaList(typ int32) bool { |
|
return typ == int32(TypeVideo) || typ == int32(TypeMusicNew) |
|
} |
|
|
|
type Favorite struct { |
|
ID int64 `json:"id"` |
|
Oid int64 `json:"oid"` |
|
Mid int64 `json:"mid"` |
|
Fid int64 `json:"fid"` |
|
Type int8 `json:"type"` |
|
State int8 `json:"state"` |
|
CTime time.Time `json:"ctime"` |
|
MTime time.Time `json:"mtime"` |
|
Sequence uint64 `json:"sequence"` |
|
} |
|
|
|
func (f *Favorite) ResourceID() int64 { |
|
return int64(f.Oid)*100 + int64(f.Type) |
|
} |
|
|
|
type Favorites struct { |
|
Page struct { |
|
Num int `json:"num"` |
|
Size int `json:"size"` |
|
Count int `json:"count"` |
|
} `json:"page"` |
|
List []*Favorite `json:"list"` |
|
} |
|
|
|
type User struct { |
|
ID int64 `json:"id"` |
|
Oid int64 `json:"oid"` |
|
Mid int64 `json:"mid"` |
|
Type int8 `json:"type"` |
|
State int8 `json:"state"` |
|
CTime time.Time `json:"ctime"` |
|
MTime time.Time `json:"mtime"` |
|
} |
|
type UserList struct { |
|
Page struct { |
|
Num int `json:"num"` |
|
Size int `json:"size"` |
|
Total int `json:"total"` |
|
} `json:"page"` |
|
List []*User `json:"list"` |
|
} |
|
|
|
// AttrVal get attr val by bit. |
|
func (f *Folder) AttrVal(bit uint) int32 { |
|
return (f.Attr >> bit) & int32(1) |
|
} |
|
|
|
// AttrSet set attr value by bit. |
|
func (f *Folder) AttrSet(v int32, bit uint) { |
|
f.Attr = f.Attr&(^(1 << bit)) | (v << bit) |
|
} |
|
|
|
// IsDefault return true if folder is default. |
|
func (f *Folder) IsDefault() bool { |
|
return f.Attr&AttrBitNoDefault == int32(0) |
|
} |
|
|
|
// IsPublic return true if folder is public. |
|
func (f *Folder) IsPublic() bool { |
|
return f.AttrVal(AttrBitPublic) == AttrIsPublic |
|
} |
|
|
|
// Access return true if the user has the access permission to the folder. |
|
func (f *Folder) Access(mid int64) bool { |
|
return f.IsPublic() || f.Mid == mid |
|
} |
|
|
|
// IsLimited return true if folder count is eq or gt conf limit. |
|
func (f *Folder) IsLimited(cnt int, defaultLimit int, normalLimit int) bool { |
|
switch f.IsDefault() { |
|
case true: |
|
return f.Count+cnt > defaultLimit |
|
case false: |
|
return f.Count+cnt > normalLimit |
|
} |
|
return true |
|
} |
|
|
|
func (f *Folder) MediaID() int64 { |
|
return f.ID*100 + f.Mid%100 |
|
} |
|
|
|
func CheckArg(tp int8, oid int64) error { |
|
if tp <= 0 || oid <= 0 { |
|
return errors.New("negative number and zero not allowed") |
|
} |
|
return CheckType(tp) |
|
} |
|
|
|
func CheckType(typ int8) error { |
|
if typ < Article || typ > TypeMax { |
|
return errors.New("type code out of range") |
|
} |
|
return nil |
|
} |
|
|
|
// CompleteURL adds host on path. |
|
func CompleteURL(path string) (url string) { |
|
if path == "" { |
|
// url = "http://static.hdslb.com/images/transparent.gif" |
|
return |
|
} |
|
url = path |
|
if strings.Index(path, "//") == 0 || strings.Index(path, "http://") == 0 || strings.Index(path, "https://") == 0 { |
|
return |
|
} |
|
url = "https://i0.hdslb.com" + url |
|
return |
|
} |
|
|
|
// CleanURL cuts host. |
|
func CleanURL(url string) (path string) { |
|
path = url |
|
if strings.Index(url, "//") == 0 { |
|
path = url[14:] |
|
} else if strings.Index(url, "http://") == 0 { |
|
path = url[19:] |
|
} else if strings.Index(url, "https://") == 0 { |
|
path = url[20:] |
|
} |
|
return |
|
} |
|
|
|
// Folders . |
|
type Folders []*Folder |
|
|
|
func (f Folders) Len() int { return len(f) } |
|
|
|
func (f Folders) Less(i, j int) bool { |
|
if f[i].IsDefault() { |
|
return true |
|
} |
|
if f[j].IsDefault() { |
|
return false |
|
} |
|
if f[i].ID > f[j].ID { |
|
return true |
|
} |
|
return false |
|
} |
|
|
|
func (f Folders) Swap(i, j int) { f[i], f[j] = f[j], f[i] } |
|
|
|
// FolderSort folder index. |
|
type FolderSort struct { |
|
ID int64 `json:"id"` |
|
Type int8 `json:"type"` |
|
Mid int64 `json:"mid"` |
|
Sort []int64 `json:"sort"` |
|
Map map[int64]struct{} `json:"-"` |
|
CTime time.Time `json:"ctime"` |
|
MTime time.Time `json:"mtime"` |
|
} |
|
|
|
// Index return index for fids. |
|
func (f *FolderSort) Index() []byte { |
|
var ( |
|
i int |
|
v int64 |
|
fs = f.Sort |
|
n = len(fs) * 8 |
|
b = make([]byte, n) |
|
) |
|
for i = 0; i < n; i += 8 { |
|
v = fs[i/8] |
|
b[i] = byte(v >> 56) |
|
b[i+1] = byte(v >> 48) |
|
b[i+2] = byte(v >> 40) |
|
b[i+3] = byte(v >> 32) |
|
b[i+4] = byte(v >> 24) |
|
b[i+5] = byte(v >> 16) |
|
b[i+6] = byte(v >> 8) |
|
b[i+7] = byte(v) |
|
} |
|
return b |
|
} |
|
|
|
// SetIndex set sort fids. |
|
func (f *FolderSort) SetIndex(b []byte) (err error) { |
|
var ( |
|
i int |
|
id int64 |
|
n = len(b) |
|
ids = make([]int64, n/8) |
|
) |
|
if len(b)%8 != 0 { |
|
err = fmt.Errorf("invalid sort index:%v", b) |
|
return |
|
} |
|
f.Map = make(map[int64]struct{}, n) |
|
for i = 0; i < n; i += 8 { |
|
id = int64(b[i+7]) | |
|
int64(b[i+6])<<8 | |
|
int64(b[i+5])<<16 | |
|
int64(b[i+4])<<24 | |
|
int64(b[i+3])<<32 | |
|
int64(b[i+2])<<40 | |
|
int64(b[i+1])<<48 | |
|
int64(b[i])<<56 |
|
ids[i/8] = id |
|
f.Map[id] = struct{}{} |
|
} |
|
f.Sort = ids |
|
return |
|
} |
|
|
|
// ToBytes return []byte for ids. |
|
func ToBytes(ids []int64) []byte { |
|
var ( |
|
i int |
|
v int64 |
|
n = len(ids) * 8 |
|
b = make([]byte, n) |
|
) |
|
for i = 0; i < n; i += 8 { |
|
v = ids[i/8] |
|
b[i] = byte(v >> 56) |
|
b[i+1] = byte(v >> 48) |
|
b[i+2] = byte(v >> 40) |
|
b[i+3] = byte(v >> 32) |
|
b[i+4] = byte(v >> 24) |
|
b[i+5] = byte(v >> 16) |
|
b[i+6] = byte(v >> 8) |
|
b[i+7] = byte(v) |
|
} |
|
return b |
|
} |
|
|
|
// ToInt64s bytes to int64s. |
|
func ToInt64s(b []byte) (ids []int64, err error) { |
|
var ( |
|
i int |
|
id int64 |
|
n = len(b) |
|
) |
|
ids = make([]int64, n/8) |
|
if len(b)%8 != 0 { |
|
err = fmt.Errorf("invalid bytes:%v", b) |
|
return |
|
} |
|
for i = 0; i < n; i += 8 { |
|
id = int64(b[i+7]) | |
|
int64(b[i+6])<<8 | |
|
int64(b[i+5])<<16 | |
|
int64(b[i+4])<<24 | |
|
int64(b[i+3])<<32 | |
|
int64(b[i+2])<<40 | |
|
int64(b[i+1])<<48 | |
|
int64(b[i])<<56 |
|
ids[i/8] = id |
|
} |
|
return |
|
} |
|
|
|
// SortFolders sort the favorites by index. |
|
func (f *FolderSort) SortFolders(fs map[int64]*Folder, isSelf bool) (res []*Folder, update bool) { |
|
var ( |
|
ok bool |
|
id int64 |
|
sorted []int64 |
|
fav *Folder |
|
idx = f.Sort |
|
) |
|
res = make([]*Folder, 0, len(fs)) |
|
if len(f.Sort) == 0 { |
|
for _, fav = range fs { |
|
if !isSelf && !fav.IsPublic() { |
|
continue |
|
} |
|
res = append(res, fav) |
|
} |
|
sort.Sort(Folders(res)) |
|
return |
|
} |
|
if len(idx) != len(fs) { |
|
sorted = append(sorted, idx[0]) |
|
for id = range fs { |
|
if _, ok = f.Map[id]; !ok { |
|
sorted = append(sorted, id) |
|
} |
|
} |
|
for _, id := range idx[1:] { |
|
if _, ok = fs[id]; ok { |
|
sorted = append(sorted, id) |
|
} |
|
} |
|
update = true |
|
f.Sort = sorted |
|
} |
|
for _, id = range f.Sort { |
|
if fav, ok = fs[id]; ok { |
|
if !isSelf && !fav.IsPublic() { |
|
continue |
|
} |
|
res = append(res, fav) |
|
} |
|
} |
|
return |
|
}
|
|
|