ajout app

This commit is contained in:
2024-04-17 20:22:30 +02:00
parent cc017cfc5e
commit f9d05a2fd3
8025 changed files with 729805 additions and 0 deletions

View File

@ -0,0 +1,572 @@
package repo
import (
"errors"
"time"
"voltaserve/errorpkg"
"voltaserve/helper"
"voltaserve/infra"
"voltaserve/model"
"gorm.io/gorm"
)
type FileInsertOptions struct {
Name string
WorkspaceID string
ParentID *string
Type string
}
type FileRepo interface {
Insert(opts FileInsertOptions) (model.File, error)
Find(id string) (model.File, error)
FindChildren(id string) ([]model.File, error)
FindPath(id string) ([]model.File, error)
FindTree(id string) ([]model.File, error)
GetIDsByWorkspace(workspaceID string) ([]string, error)
AssignSnapshots(cloneID string, originalID string) error
MoveSourceIntoTarget(targetID string, sourceID string) error
Save(file model.File) error
BulkInsert(values []model.File, chunkSize int) error
BulkInsertPermissions(values []*UserPermission, chunkSize int) error
Delete(id string) error
GetChildrenIDs(id string) ([]string, error)
GetItemCount(id string) (int64, error)
IsGrandChildOf(id string, ancestorID string) (bool, error)
GetSize(id string) (int64, error)
GrantUserPermission(id string, userID string, permission string) error
RevokeUserPermission(id string, userID string) error
GrantGroupPermission(id string, groupID string, permission string) error
RevokeGroupPermission(id string, groupID string) error
}
func NewFileRepo() FileRepo {
return newFileRepo()
}
func NewFile() model.File {
return &fileEntity{}
}
type fileEntity struct {
ID string `json:"id" gorm:"column:id"`
WorkspaceID string `json:"workspaceId" gorm:"column:workspace_id"`
Name string `json:"name" gorm:"column:name"`
Type string `json:"type" gorm:"column:type"`
ParentID *string `json:"parentId,omitempty" gorm:"column:parent_id"`
Snapshots []*snapshotEntity `json:"snapshots,omitempty" gorm:"-"`
UserPermissions []*userPermissionValue `json:"userPermissions" gorm:"-"`
GroupPermissions []*groupPermissionValue `json:"groupPermissions" gorm:"-"`
Text *string `json:"text,omitempty" gorm:"-"`
CreateTime string `json:"createTime" gorm:"column:create_time"`
UpdateTime *string `json:"updateTime,omitempty" gorm:"column:update_time"`
}
func (*fileEntity) TableName() string {
return "file"
}
func (f *fileEntity) BeforeCreate(*gorm.DB) (err error) {
f.CreateTime = time.Now().UTC().Format(time.RFC3339)
return nil
}
func (f *fileEntity) BeforeSave(*gorm.DB) (err error) {
timeNow := time.Now().UTC().Format(time.RFC3339)
f.UpdateTime = &timeNow
return nil
}
func (f *fileEntity) GetID() string {
return f.ID
}
func (f *fileEntity) GetWorkspaceID() string {
return f.WorkspaceID
}
func (f *fileEntity) GetName() string {
return f.Name
}
func (f *fileEntity) GetType() string {
return f.Type
}
func (f *fileEntity) GetParentID() *string {
return f.ParentID
}
func (f *fileEntity) GetSnapshots() []model.Snapshot {
var res []model.Snapshot
for _, s := range f.Snapshots {
res = append(res, s)
}
return res
}
func (f *fileEntity) GetUserPermissions() []model.CoreUserPermission {
var res []model.CoreUserPermission
for _, p := range f.UserPermissions {
res = append(res, p)
}
return res
}
func (f *fileEntity) GetGroupPermissions() []model.CoreGroupPermission {
var res []model.CoreGroupPermission
for _, p := range f.GroupPermissions {
res = append(res, p)
}
return res
}
func (f *fileEntity) GetText() *string {
return f.Text
}
func (f *fileEntity) GetCreateTime() string {
return f.CreateTime
}
func (f *fileEntity) GetUpdateTime() *string {
return f.UpdateTime
}
func (f *fileEntity) SetID(id string) {
f.ID = id
}
func (f *fileEntity) SetParentID(parentID *string) {
f.ParentID = parentID
}
func (f *fileEntity) SetWorkspaceID(workspaceID string) {
f.WorkspaceID = workspaceID
}
func (f *fileEntity) SetType(fileType string) {
f.Type = fileType
}
func (f *fileEntity) SetName(name string) {
f.Name = name
}
func (f *fileEntity) SetText(text *string) {
f.Text = text
}
func (f *fileEntity) SetCreateTime(createTime string) {
f.CreateTime = createTime
}
func (f *fileEntity) SetUpdateTime(updateTime *string) {
f.UpdateTime = updateTime
}
type fileRepo struct {
db *gorm.DB
snapshotRepo *snapshotRepo
permissionRepo *permissionRepo
}
func newFileRepo() *fileRepo {
return &fileRepo{
db: infra.GetDb(),
snapshotRepo: newSnapshotRepo(),
permissionRepo: newPermissionRepo(),
}
}
func (repo *fileRepo) Insert(opts FileInsertOptions) (model.File, error) {
id := helper.NewID()
file := fileEntity{
ID: id,
WorkspaceID: opts.WorkspaceID,
Name: opts.Name,
Type: opts.Type,
ParentID: opts.ParentID,
}
if db := repo.db.Save(&file); db.Error != nil {
return nil, db.Error
}
res, err := repo.find(id)
if err != nil {
return nil, err
}
if err := repo.populateModelFields([]*fileEntity{res}); err != nil {
return nil, err
}
return res, nil
}
func (repo *fileRepo) Find(id string) (model.File, error) {
file, err := repo.find(id)
if err != nil {
return nil, err
}
if err := repo.populateModelFields([]*fileEntity{file}); err != nil {
return nil, err
}
return file, nil
}
func (repo *fileRepo) find(id string) (*fileEntity, error) {
var res = fileEntity{}
db := repo.db.Raw("SELECT * FROM file WHERE id = ?", id).Scan(&res)
if db.Error != nil {
if errors.Is(db.Error, gorm.ErrRecordNotFound) {
return nil, errorpkg.NewFileNotFoundError(db.Error)
} else {
return nil, errorpkg.NewInternalServerError(db.Error)
}
}
if len(res.ID) == 0 {
return nil, errorpkg.NewFileNotFoundError(db.Error)
}
return &res, nil
}
func (repo *fileRepo) FindChildren(id string) ([]model.File, error) {
var entities []*fileEntity
db := repo.db.Raw("SELECT * FROM file WHERE parent_id = ? ORDER BY create_time ASC", id).Scan(&entities)
if db.Error != nil {
return nil, db.Error
}
if err := repo.populateModelFields(entities); err != nil {
return nil, err
}
var res []model.File
for _, f := range entities {
res = append(res, f)
}
return res, nil
}
func (repo *fileRepo) FindPath(id string) ([]model.File, error) {
var entities []*fileEntity
if db := repo.db.
Raw("WITH RECURSIVE rec (id, name, type, parent_id, workspace_id, create_time, update_time) AS "+
"(SELECT f.id, f.name, f.type, f.parent_id, f.workspace_id, f.create_time, f.update_time FROM file f WHERE f.id = ? "+
"UNION SELECT f.id, f.name, f.type, f.parent_id, f.workspace_id, f.create_time, f.update_time FROM rec, file f WHERE f.id = rec.parent_id) "+
"SELECT * FROM rec", id).
Scan(&entities); db.Error != nil {
return nil, db.Error
}
if err := repo.populateModelFields(entities); err != nil {
return nil, err
}
var res []model.File
for _, f := range entities {
res = append(res, f)
}
return res, nil
}
func (repo *fileRepo) FindTree(id string) ([]model.File, error) {
var entities []*fileEntity
db := repo.db.
Raw("WITH RECURSIVE rec (id, name, type, parent_id, workspace_id, create_time, update_time) AS "+
"(SELECT f.id, f.name, f.type, f.parent_id, f.workspace_id, f.create_time, f.update_time FROM file f WHERE f.id = ? "+
"UNION SELECT f.id, f.name, f.type, f.parent_id, f.workspace_id, f.create_time, f.update_time FROM rec, file f WHERE f.parent_id = rec.id) "+
"SELECT rec.* FROM rec ORDER BY create_time ASC", id).
Scan(&entities)
if db.Error != nil {
return nil, db.Error
}
if err := repo.populateModelFields(entities); err != nil {
return nil, err
}
var res []model.File
for _, f := range entities {
res = append(res, f)
}
return res, nil
}
func (repo *fileRepo) GetIDsByWorkspace(workspaceID string) ([]string, error) {
type IDResult struct {
Result string
}
var ids []IDResult
db := repo.db.Raw("SELECT id result FROM file WHERE workspace_id = ? ORDER BY create_time ASC", workspaceID).Scan(&ids)
if db.Error != nil {
return nil, db.Error
}
res := []string{}
for _, id := range ids {
res = append(res, id.Result)
}
return res, nil
}
func (repo *fileRepo) AssignSnapshots(cloneID string, originalID string) error {
if db := repo.db.Exec("INSERT INTO snapshot_file (snapshot_id, file_id) SELECT s.id, ? "+
"FROM snapshot s LEFT JOIN snapshot_file map ON s.id = map.snapshot_id "+
"WHERE map.file_id = ? ORDER BY s.version DESC LIMIT 1", cloneID, originalID); db.Error != nil {
return db.Error
}
return nil
}
func (repo *fileRepo) MoveSourceIntoTarget(targetID string, sourceID string) error {
if db := repo.db.Exec("UPDATE file SET parent_id = ? WHERE id = ?", targetID, sourceID); db.Error != nil {
return db.Error
}
return nil
}
func (repo *fileRepo) Save(file model.File) error {
if db := repo.db.Save(file); db.Error != nil {
return db.Error
}
return nil
}
func (repo *fileRepo) BulkInsert(values []model.File, chunkSize int) error {
var entities []*fileEntity
for _, f := range values {
entities = append(entities, f.(*fileEntity))
}
if db := repo.db.CreateInBatches(entities, chunkSize); db.Error != nil {
return db.Error
}
return nil
}
func (repo *fileRepo) BulkInsertPermissions(values []*UserPermission, chunkSize int) error {
if db := repo.db.CreateInBatches(values, chunkSize); db.Error != nil {
return db.Error
}
return nil
}
func (repo *fileRepo) Delete(id string) error {
db := repo.db.Exec("DELETE FROM file WHERE id = ?", id)
if db.Error != nil {
return db.Error
}
db = repo.db.Exec("DELETE FROM userpermission WHERE resource_id = ?", id)
if db.Error != nil {
return db.Error
}
db = repo.db.Exec("DELETE FROM grouppermission WHERE resource_id = ?", id)
if db.Error != nil {
return db.Error
}
return nil
}
func (repo *fileRepo) GetChildrenIDs(id string) ([]string, error) {
type Result struct {
Result string
}
var results []Result
db := repo.db.Raw("SELECT id result FROM file WHERE parent_id = ? ORDER BY create_time ASC", id).Scan(&results)
if db.Error != nil {
return []string{}, db.Error
}
res := []string{}
for _, v := range results {
res = append(res, v.Result)
}
return res, nil
}
func (repo *fileRepo) GetItemCount(id string) (int64, error) {
type Result struct {
Result int64
}
var res Result
db := repo.db.
Raw("WITH RECURSIVE rec (id, parent_id) AS "+
"(SELECT f.id, f.parent_id FROM file f WHERE f.id = ? "+
"UNION SELECT f.id, f.parent_id FROM rec, file f WHERE f.parent_id = rec.id) "+
"SELECT count(rec.id) as result FROM rec", id).
Scan(&res)
if db.Error != nil {
return 0, db.Error
}
return res.Result - 1, nil
}
func (repo *fileRepo) IsGrandChildOf(id string, ancestorID string) (bool, error) {
type Result struct {
Result bool
}
var res Result
if db := repo.db.
Raw("WITH RECURSIVE rec (id, parent_id) AS "+
"(SELECT f.id, f.parent_id FROM file f WHERE f.id = ? "+
"UNION SELECT f.id, f.parent_id FROM rec, file f WHERE f.parent_id = rec.id) "+
"SELECT count(rec.id) > 0 as result FROM rec WHERE rec.id = ?", ancestorID, id).
Scan(&res); db.Error != nil {
return false, db.Error
}
return res.Result, nil
}
func (repo *fileRepo) GetSize(id string) (int64, error) {
type Result struct {
Result int64
}
var res Result
db := repo.db.
Raw("WITH RECURSIVE rec (id, parent_id) AS "+
"(SELECT f.id, f.parent_id FROM file f WHERE f.id = ? "+
"UNION SELECT f.id, f.parent_id FROM rec, file f WHERE f.parent_id = rec.id) "+
"SELECT coalesce(sum((s.original->>'size')::int), 0) as result FROM snapshot s, rec "+
"LEFT JOIN snapshot_file map ON rec.id = map.file_id WHERE map.snapshot_id = s.id", id).
Scan(&res)
if db.Error != nil {
return res.Result, db.Error
}
return res.Result, nil
}
func (repo *fileRepo) GrantUserPermission(id string, userID string, permission string) error {
/* Grant permission to workspace */
db := repo.db.Exec("INSERT INTO userpermission (id, user_id, resource_id, permission) "+
"(SELECT ?, ?, w.id, 'viewer' FROM file f "+
"INNER JOIN workspace w ON w.id = f.workspace_id AND f.id = ?) "+
"ON CONFLICT DO NOTHING",
helper.NewID(), userID, id)
if db.Error != nil {
return db.Error
}
/* Grant 'viewer' permission to path files */
path, err := repo.FindPath(id)
if err != nil {
return err
}
for _, f := range path {
db := repo.db.Exec("INSERT INTO userpermission (id, user_id, resource_id, permission) "+
"VALUES (?, ?, ?, 'viewer') ON CONFLICT DO NOTHING",
helper.NewID(), userID, f.GetID())
if db.Error != nil {
return db.Error
}
}
/* Grant the requested permission to tree files */
tree, err := repo.FindTree(id)
if err != nil {
return err
}
for _, f := range tree {
db := repo.db.Exec("INSERT INTO userpermission (id, user_id, resource_id, permission) "+
"VALUES (?, ?, ?, ?) ON CONFLICT (user_id, resource_id) DO UPDATE SET permission = ?",
helper.NewID(), userID, f.GetID(), permission, permission)
if db.Error != nil {
return db.Error
}
}
return nil
}
func (repo *fileRepo) RevokeUserPermission(id string, userID string) error {
tree, err := repo.FindTree(id)
if err != nil {
return err
}
for _, f := range tree {
db := repo.db.Exec("DELETE FROM userpermission WHERE user_id = ? AND resource_id = ?", userID, f.GetID())
if db.Error != nil {
return db.Error
}
}
return nil
}
func (repo *fileRepo) GrantGroupPermission(id string, groupID string, permission string) error {
/* Grant permission to workspace */
db := repo.db.Exec("INSERT INTO grouppermission (id, group_id, resource_id, permission) "+
"(SELECT ?, ?, w.id, 'viewer' FROM file f "+
"INNER JOIN workspace w ON w.id = f.workspace_id AND f.id = ?) "+
"ON CONFLICT DO NOTHING",
helper.NewID(), groupID, id)
if db.Error != nil {
return db.Error
}
/* Grant 'viewer' permission to path files */
path, err := repo.FindPath(id)
if err != nil {
return err
}
for _, f := range path {
db := repo.db.Exec("INSERT INTO grouppermission (id, group_id, resource_id, permission) "+
"VALUES (?, ?, ?, 'viewer') ON CONFLICT DO NOTHING",
helper.NewID(), groupID, f.GetID())
if db.Error != nil {
return db.Error
}
}
/* Grant the requested permission to tree files */
tree, err := repo.FindTree(id)
if err != nil {
return err
}
for _, f := range tree {
db := repo.db.Exec("INSERT INTO grouppermission (id, group_id, resource_id, permission) "+
"VALUES (?, ?, ?, ?) ON CONFLICT (group_id, resource_id) DO UPDATE SET permission = ?",
helper.NewID(), groupID, f.GetID(), permission, permission)
if db.Error != nil {
return db.Error
}
}
return nil
}
func (repo *fileRepo) RevokeGroupPermission(id string, groupID string) error {
tree, err := repo.FindTree(id)
if err != nil {
return err
}
for _, f := range tree {
db := repo.db.Exec("DELETE FROM grouppermission WHERE group_id = ? AND resource_id = ?", groupID, f.GetID())
if db.Error != nil {
return db.Error
}
}
return nil
}
func (repo *fileRepo) populateModelFields(entities []*fileEntity) error {
for _, f := range entities {
f.UserPermissions = make([]*userPermissionValue, 0)
userPermissions, err := repo.permissionRepo.GetUserPermissions(f.ID)
if err != nil {
return err
}
for _, p := range userPermissions {
f.UserPermissions = append(f.UserPermissions, &userPermissionValue{
UserID: p.UserID,
Value: p.Permission,
})
}
f.GroupPermissions = make([]*groupPermissionValue, 0)
groupPermissions, err := repo.permissionRepo.GetGroupPermissions(f.ID)
if err != nil {
return err
}
for _, p := range groupPermissions {
f.GroupPermissions = append(f.GroupPermissions, &groupPermissionValue{
GroupID: p.GroupID,
Value: p.Permission,
})
}
snapshots, err := repo.snapshotRepo.findAllForFile(f.ID)
if err != nil {
return nil
}
f.Snapshots = snapshots
}
return nil
}

View File

@ -0,0 +1,344 @@
package repo
import (
"errors"
"time"
"voltaserve/errorpkg"
"voltaserve/helper"
"voltaserve/infra"
"voltaserve/model"
"gorm.io/gorm"
)
type GroupInsertOptions struct {
ID string
Name string
OrganizationID string
OwnerID string
}
type GroupRepo interface {
Insert(opts GroupInsertOptions) (model.Group, error)
Find(id string) (model.Group, error)
GetIDsForFile(fileID string) ([]string, error)
GetIDsForUser(userID string) ([]string, error)
GetIDsForOrganization(id string) ([]string, error)
Save(group model.Group) error
Delete(id string) error
AddUser(id string, userID string) error
RemoveMember(id string, userID string) error
GetIDs() ([]string, error)
GetMembers(id string) ([]model.User, error)
GrantUserPermission(id string, userID string, permission string) error
RevokeUserPermission(id string, userID string) error
}
func NewGroupRepo() GroupRepo {
return newGroupRepo()
}
func NewGroup() model.Group {
return &groupEntity{}
}
type groupEntity struct {
ID string `json:"id" gorm:"column:id"`
Name string `json:"name" gorm:"column:name"`
OrganizationID string `json:"organizationId" gorm:"column:organization_id"`
UserPermissions []*userPermissionValue `json:"userPermissions" gorm:"-"`
GroupPermissions []*groupPermissionValue `json:"groupPermissions" gorm:"-"`
Members []string `json:"members" gorm:"-"`
CreateTime string `json:"createTime" gorm:"column:create_time"`
UpdateTime *string `json:"updateTime" gorm:"column:update_time"`
}
func (*groupEntity) TableName() string {
return "group"
}
func (g *groupEntity) BeforeCreate(*gorm.DB) (err error) {
g.CreateTime = time.Now().UTC().Format(time.RFC3339)
return nil
}
func (g *groupEntity) BeforeSave(*gorm.DB) (err error) {
timeNow := time.Now().UTC().Format(time.RFC3339)
g.UpdateTime = &timeNow
return nil
}
func (g *groupEntity) GetID() string {
return g.ID
}
func (g *groupEntity) GetName() string {
return g.Name
}
func (g *groupEntity) GetOrganizationID() string {
return g.OrganizationID
}
func (g *groupEntity) GetUserPermissions() []model.CoreUserPermission {
var res []model.CoreUserPermission
for _, p := range g.UserPermissions {
res = append(res, p)
}
return res
}
func (g *groupEntity) GetGroupPermissions() []model.CoreGroupPermission {
var res []model.CoreGroupPermission
for _, p := range g.GroupPermissions {
res = append(res, p)
}
return res
}
func (g *groupEntity) GetUsers() []string {
return g.Members
}
func (g *groupEntity) GetCreateTime() string {
return g.CreateTime
}
func (g *groupEntity) GetUpdateTime() *string {
return g.UpdateTime
}
func (g *groupEntity) SetName(name string) {
g.Name = name
}
func (g *groupEntity) SetUpdateTime(updateTime *string) {
g.UpdateTime = updateTime
}
type groupRepo struct {
db *gorm.DB
permissionRepo *permissionRepo
}
func newGroupRepo() *groupRepo {
return &groupRepo{
db: infra.GetDb(),
permissionRepo: newPermissionRepo(),
}
}
func (repo *groupRepo) Insert(opts GroupInsertOptions) (model.Group, error) {
group := groupEntity{
ID: opts.ID,
Name: opts.Name,
OrganizationID: opts.OrganizationID,
}
if db := repo.db.Save(&group); db.Error != nil {
return nil, db.Error
}
res, err := repo.Find(opts.ID)
if err != nil {
return nil, err
}
return res, nil
}
func (repo *groupRepo) find(id string) (*groupEntity, error) {
var res = groupEntity{}
db := repo.db.Where("id = ?", id).First(&res)
if db.Error != nil {
if errors.Is(db.Error, gorm.ErrRecordNotFound) {
return nil, errorpkg.NewGroupNotFoundError(db.Error)
} else {
return nil, errorpkg.NewInternalServerError(db.Error)
}
}
return &res, nil
}
func (repo *groupRepo) Find(id string) (model.Group, error) {
group, err := repo.find(id)
if err != nil {
return nil, err
}
if err := repo.populateModelFields([]*groupEntity{group}); err != nil {
return nil, err
}
return group, nil
}
func (repo *groupRepo) GetIDsForFile(fileID string) ([]string, error) {
type Result struct {
Result string
}
var results []Result
db := repo.db.
Raw(`SELECT DISTINCT g.id as result FROM "group" g INNER JOIN grouppermission p ON p.resource_id = ? WHERE p.group_id = g.id`, fileID).
Scan(&results)
if db.Error != nil {
return []string{}, db.Error
}
res := []string{}
for _, v := range results {
res = append(res, v.Result)
}
return res, nil
}
func (repo *groupRepo) GetIDsForUser(userID string) ([]string, error) {
type Result struct {
Result string
}
var results []Result
db := repo.db.Raw(`SELECT group_id from group_user WHERE user_id = ?`, userID).Scan(&results)
if db.Error != nil {
return []string{}, db.Error
}
res := []string{}
for _, v := range results {
res = append(res, v.Result)
}
return res, nil
}
func (repo *groupRepo) GetIDsForOrganization(id string) ([]string, error) {
type Result struct {
Result string
}
var results []Result
db := repo.db.Raw(`SELECT id as result from "group" WHERE organization_id = ?`, id).Scan(&results)
if db.Error != nil {
return []string{}, db.Error
}
res := []string{}
for _, v := range results {
res = append(res, v.Result)
}
return res, nil
}
func (repo *groupRepo) Save(group model.Group) error {
db := repo.db.Save(group)
if db.Error != nil {
return db.Error
}
return nil
}
func (repo *groupRepo) Delete(id string) error {
db := repo.db.Exec(`DELETE FROM "group" WHERE id = ?`, id)
if db.Error != nil {
return db.Error
}
db = repo.db.Exec("DELETE FROM userpermission WHERE resource_id = ?", id)
if db.Error != nil {
return db.Error
}
db = repo.db.Exec("DELETE FROM grouppermission WHERE resource_id = ?", id)
if db.Error != nil {
return db.Error
}
return nil
}
func (repo *groupRepo) AddUser(id string, userID string) error {
db := repo.db.Exec("INSERT INTO group_user (group_id, user_id) VALUES (?, ?)", id, userID)
if db.Error != nil {
return db.Error
}
return nil
}
func (repo *groupRepo) RemoveMember(id string, userID string) error {
db := repo.db.Exec("DELETE FROM group_user WHERE group_id = ? AND user_id = ?", id, userID)
if db.Error != nil {
return db.Error
}
return nil
}
func (repo *groupRepo) GetIDs() ([]string, error) {
type Result struct {
Result string
}
var results []Result
db := repo.db.Raw(`SELECT id result FROM "group" ORDER BY create_time DESC`).Scan(&results)
if db.Error != nil {
return []string{}, db.Error
}
res := []string{}
for _, v := range results {
res = append(res, v.Result)
}
return res, nil
}
func (repo *groupRepo) GetMembers(id string) ([]model.User, error) {
var entities []*userEntity
db := repo.db.
Raw(`SELECT DISTINCT u.* FROM "user" u INNER JOIN group_user gu ON u.id = gu.user_id WHERE gu.group_id = ?`, id).
Scan(&entities)
if db.Error != nil {
return nil, db.Error
}
var res []model.User
for _, u := range entities {
res = append(res, u)
}
return res, nil
}
func (repo *groupRepo) GrantUserPermission(id string, userID string, permission string) error {
db := repo.db.Exec(
"INSERT INTO userpermission (id, user_id, resource_id, permission) VALUES (?, ?, ?, ?) ON CONFLICT (user_id, resource_id) DO UPDATE SET permission = ?",
helper.NewID(), userID, id, permission, permission)
if db.Error != nil {
return db.Error
}
return nil
}
func (repo *groupRepo) RevokeUserPermission(id string, userID string) error {
db := repo.db.Exec("DELETE FROM userpermission WHERE user_id = ? AND resource_id = ?", userID, id)
if db.Error != nil {
return db.Error
}
return nil
}
func (repo *groupRepo) populateModelFields(groups []*groupEntity) error {
for _, g := range groups {
g.UserPermissions = make([]*userPermissionValue, 0)
userPermissions, err := repo.permissionRepo.GetUserPermissions(g.ID)
if err != nil {
return err
}
for _, p := range userPermissions {
g.UserPermissions = append(g.UserPermissions, &userPermissionValue{
UserID: p.UserID,
Value: p.Permission,
})
}
g.GroupPermissions = make([]*groupPermissionValue, 0)
groupPermissions, err := repo.permissionRepo.GetGroupPermissions(g.ID)
if err != nil {
return err
}
for _, p := range groupPermissions {
g.GroupPermissions = append(g.GroupPermissions, &groupPermissionValue{
GroupID: p.GroupID,
Value: p.Permission,
})
}
members, err := repo.GetMembers(g.ID)
if err != nil {
return nil
}
g.Members = make([]string, 0)
for _, u := range members {
g.Members = append(g.Members, u.GetID())
}
}
return nil
}

View File

@ -0,0 +1,185 @@
package repo
import (
"errors"
"time"
"voltaserve/errorpkg"
"voltaserve/helper"
"voltaserve/infra"
"voltaserve/model"
"gorm.io/gorm"
)
type InvitationInsertOptions struct {
UserID string
OrganizationID string
Emails []string
}
type InvitationRepo interface {
Insert(opts InvitationInsertOptions) ([]model.Invitation, error)
Find(id string) (model.Invitation, error)
GetIncoming(email string) ([]model.Invitation, error)
GetOutgoing(orgID string, userID string) ([]model.Invitation, error)
Save(org model.Invitation) error
Delete(id string) error
}
func NewInvitationRepo() InvitationRepo {
return newInvitationRepo()
}
type invitationEntity struct {
ID string `json:"id" gorm:"column:id"`
OrganizationID string `json:"organizationId" gorm:"column:organization_id"`
OwnerID string `json:"ownerId" gorm:"column:owner_id"`
Email string `json:"email" gorm:"column:email"`
Status string `json:"status" gorm:"column:status"`
CreateTime string `json:"createTime" gorm:"column:create_time"`
UpdateTime *string `json:"updateTime" gorm:"column:update_time"`
}
func (*invitationEntity) TableName() string {
return "invitation"
}
func (i *invitationEntity) BeforeCreate(*gorm.DB) (err error) {
i.CreateTime = time.Now().UTC().Format(time.RFC3339)
return nil
}
func (i *invitationEntity) BeforeSave(*gorm.DB) (err error) {
timeNow := time.Now().UTC().Format(time.RFC3339)
i.UpdateTime = &timeNow
return nil
}
func (i *invitationEntity) GetID() string {
return i.ID
}
func (i *invitationEntity) GetOrganizationID() string {
return i.OrganizationID
}
func (i *invitationEntity) GetOwnerID() string {
return i.OwnerID
}
func (i *invitationEntity) GetEmail() string {
return i.Email
}
func (i *invitationEntity) GetStatus() string {
return i.Status
}
func (i *invitationEntity) GetCreateTime() string {
return i.CreateTime
}
func (i *invitationEntity) GetUpdateTime() *string {
return i.UpdateTime
}
func (i *invitationEntity) SetStatus(status string) {
i.Status = status
}
func (i *invitationEntity) SetUpdateTime(updateTime *string) {
i.UpdateTime = updateTime
}
type invitationRepo struct {
db *gorm.DB
userRepo *userRepo
}
func newInvitationRepo() *invitationRepo {
return &invitationRepo{
db: infra.GetDb(),
userRepo: newUserRepo(),
}
}
func (repo *invitationRepo) Insert(opts InvitationInsertOptions) ([]model.Invitation, error) {
var res []model.Invitation
for _, e := range opts.Emails {
invitation := invitationEntity{
ID: helper.NewID(),
OrganizationID: opts.OrganizationID,
OwnerID: opts.UserID,
Email: e,
Status: model.InvitationStatusPending,
}
if db := repo.db.Save(&invitation); db.Error != nil {
return nil, db.Error
}
i, err := repo.Find(invitation.ID)
if err != nil {
return nil, err
}
res = append(res, i)
}
return res, nil
}
func (repo *invitationRepo) Find(id string) (model.Invitation, error) {
var invitation = invitationEntity{}
db := repo.db.Where("id = ?", id).First(&invitation)
if db.Error != nil {
if errors.Is(db.Error, gorm.ErrRecordNotFound) {
return nil, errorpkg.NewInvitationNotFoundError(db.Error)
} else {
return nil, errorpkg.NewInternalServerError(db.Error)
}
}
return &invitation, nil
}
func (repo *invitationRepo) GetIncoming(email string) ([]model.Invitation, error) {
var invitations []*invitationEntity
db := repo.db.
Raw("SELECT * FROM invitation WHERE email = ? and status = 'pending' ORDER BY create_time DESC", email).
Scan(&invitations)
if db.Error != nil {
return nil, db.Error
}
var res []model.Invitation
for _, inv := range invitations {
res = append(res, inv)
}
return res, nil
}
func (repo *invitationRepo) GetOutgoing(orgID string, userID string) ([]model.Invitation, error) {
var invitations []*invitationEntity
db := repo.db.
Raw("SELECT * FROM invitation WHERE organization_id = ? and owner_id = ? ORDER BY create_time DESC", orgID, userID).
Scan(&invitations)
if db.Error != nil {
return nil, db.Error
}
var res []model.Invitation
for _, inv := range invitations {
res = append(res, inv)
}
return res, nil
}
func (repo *invitationRepo) Save(org model.Invitation) error {
db := repo.db.Save(org)
if db.Error != nil {
return db.Error
}
return nil
}
func (repo *invitationRepo) Delete(id string) error {
db := repo.db.Exec("DELETE FROM invitation WHERE id = ?", id)
if db.Error != nil {
return db.Error
}
return nil
}

View File

@ -0,0 +1,319 @@
package repo
import (
"errors"
"time"
"voltaserve/errorpkg"
"voltaserve/helper"
"voltaserve/infra"
"voltaserve/model"
"gorm.io/gorm"
)
type OrganizationInsertOptions struct {
ID string
Name string
}
type OrganizationRepo interface {
Insert(opts OrganizationInsertOptions) (model.Organization, error)
Find(id string) (model.Organization, error)
Save(org model.Organization) error
Delete(id string) error
GetIDs() ([]string, error)
AddUser(id string, userID string) error
RemoveMember(id string, userID string) error
GetMembers(id string) ([]model.User, error)
GetGroups(id string) ([]model.Group, error)
GetOwnerCount(id string) (int64, error)
GrantUserPermission(id string, userID string, permission string) error
RevokeUserPermission(id string, userID string) error
}
func NewOrganizationRepo() OrganizationRepo {
return newOrganizationRepo()
}
func NewOrganization() model.Organization {
return &organizationEntity{}
}
type organizationEntity struct {
ID string `json:"id" gorm:"column:id"`
Name string `json:"name" gorm:"column:name"`
UserPermissions []*userPermissionValue `json:"userPermissions" gorm:"-"`
GroupPermissions []*groupPermissionValue `json:"groupPermissions" gorm:"-"`
Members []string `json:"members" gorm:"-"`
CreateTime string `json:"createTime" gorm:"column:create_time"`
UpdateTime *string `json:"updateTime,omitempty" gorm:"column:update_time"`
}
func (*organizationEntity) TableName() string {
return "organization"
}
func (o *organizationEntity) BeforeCreate(*gorm.DB) (err error) {
o.CreateTime = time.Now().UTC().Format(time.RFC3339)
return nil
}
func (o *organizationEntity) BeforeSave(*gorm.DB) (err error) {
timeNow := time.Now().UTC().Format(time.RFC3339)
o.UpdateTime = &timeNow
return nil
}
func (o *organizationEntity) GetID() string {
return o.ID
}
func (o *organizationEntity) GetName() string {
return o.Name
}
func (o *organizationEntity) GetUserPermissions() []model.CoreUserPermission {
var res []model.CoreUserPermission
for _, p := range o.UserPermissions {
res = append(res, p)
}
return res
}
func (o *organizationEntity) GetGroupPermissions() []model.CoreGroupPermission {
var res []model.CoreGroupPermission
for _, p := range o.GroupPermissions {
res = append(res, p)
}
return res
}
func (o *organizationEntity) GetUsers() []string {
return o.Members
}
func (o *organizationEntity) GetCreateTime() string {
return o.CreateTime
}
func (o *organizationEntity) GetUpdateTime() *string {
return o.UpdateTime
}
func (o *organizationEntity) SetName(name string) {
o.Name = name
}
func (o *organizationEntity) SetUpdateTime(updateTime *string) {
o.UpdateTime = updateTime
}
type organizationRepo struct {
db *gorm.DB
groupRepo *groupRepo
permissionRepo *permissionRepo
}
func newOrganizationRepo() *organizationRepo {
return &organizationRepo{
db: infra.GetDb(),
groupRepo: newGroupRepo(),
permissionRepo: newPermissionRepo(),
}
}
func (repo *organizationRepo) Insert(opts OrganizationInsertOptions) (model.Organization, error) {
org := organizationEntity{
ID: opts.ID,
Name: opts.Name,
}
if db := repo.db.Save(&org); db.Error != nil {
return nil, db.Error
}
res, err := repo.Find(opts.ID)
if err != nil {
return nil, err
}
return res, nil
}
func (repo *organizationRepo) find(id string) (*organizationEntity, error) {
var res = organizationEntity{}
db := repo.db.Where("id = ?", id).First(&res)
if db.Error != nil {
if errors.Is(db.Error, gorm.ErrRecordNotFound) {
return nil, errorpkg.NewOrganizationNotFoundError(db.Error)
} else {
return nil, errorpkg.NewInternalServerError(db.Error)
}
}
return &res, nil
}
func (repo *organizationRepo) Find(id string) (model.Organization, error) {
org, err := repo.find(id)
if err != nil {
return nil, err
}
if err := repo.populateModelFields([]*organizationEntity{org}); err != nil {
return nil, err
}
return org, nil
}
func (repo *organizationRepo) Save(org model.Organization) error {
db := repo.db.Save(org)
if db.Error != nil {
return db.Error
}
return nil
}
func (repo *organizationRepo) Delete(id string) error {
db := repo.db.Exec("DELETE FROM organization WHERE id = ?", id)
if db.Error != nil {
return db.Error
}
db = repo.db.Exec("DELETE FROM userpermission WHERE resource_id = ?", id)
if db.Error != nil {
return db.Error
}
db = repo.db.Exec("DELETE FROM grouppermission WHERE resource_id = ?", id)
if db.Error != nil {
return db.Error
}
return nil
}
func (repo *organizationRepo) GetIDs() ([]string, error) {
type Result struct {
Result string
}
var results []Result
db := repo.db.Raw("SELECT id result FROM organization ORDER BY create_time DESC").Scan(&results)
if db.Error != nil {
return []string{}, db.Error
}
res := []string{}
for _, v := range results {
res = append(res, v.Result)
}
return res, nil
}
func (repo *organizationRepo) AddUser(id string, userID string) error {
db := repo.db.Exec("INSERT INTO organization_user (organization_id, user_id) VALUES (?, ?)", id, userID)
if db.Error != nil {
return db.Error
}
return nil
}
func (repo *organizationRepo) RemoveMember(id string, userID string) error {
db := repo.db.Exec("DELETE FROM organization_user WHERE organization_id = ? AND user_id = ?", id, userID)
if db.Error != nil {
return db.Error
}
return nil
}
func (repo *organizationRepo) GetMembers(id string) ([]model.User, error) {
var entities []*userEntity
db := repo.db.
Raw(`SELECT DISTINCT u.* FROM "user" u INNER JOIN organization_user ou ON u.id = ou.user_id WHERE ou.organization_id = ? ORDER BY u.full_name`, id).
Scan(&entities)
if db.Error != nil {
return nil, db.Error
}
var res []model.User
for _, u := range entities {
res = append(res, u)
}
return res, nil
}
func (repo *organizationRepo) GetGroups(id string) ([]model.Group, error) {
var entities []*groupEntity
db := repo.db.
Raw(`SELECT * FROM "group" g WHERE g.organization_id = ? ORDER BY g.name`, id).
Scan(&entities)
if db.Error != nil {
return nil, db.Error
}
if err := repo.groupRepo.populateModelFields(entities); err != nil {
return nil, err
}
var res []model.Group
for _, g := range entities {
res = append(res, g)
}
return res, nil
}
func (repo *organizationRepo) GetOwnerCount(id string) (int64, error) {
type Result struct {
Result int64
}
var res Result
db := repo.db.
Raw("SELECT count(*) as result FROM userpermission WHERE resource_id = ? and permission = ?", id, model.PermissionOwner).
Scan(&res)
if db.Error != nil {
return 0, db.Error
}
return res.Result, nil
}
func (repo *organizationRepo) GrantUserPermission(id string, userID string, permission string) error {
db := repo.db.Exec(
"INSERT INTO userpermission (id, user_id, resource_id, permission) VALUES (?, ?, ?, ?) ON CONFLICT (user_id, resource_id) DO UPDATE SET permission = ?",
helper.NewID(), userID, id, permission, permission)
if db.Error != nil {
return db.Error
}
return nil
}
func (repo *organizationRepo) RevokeUserPermission(id string, userID string) error {
db := repo.db.Exec("DELETE FROM userpermission WHERE user_id = ? AND resource_id = ?", userID, id)
if db.Error != nil {
return db.Error
}
return nil
}
func (repo *organizationRepo) populateModelFields(organizations []*organizationEntity) error {
for _, o := range organizations {
o.UserPermissions = make([]*userPermissionValue, 0)
userPermissions, err := repo.permissionRepo.GetUserPermissions(o.ID)
if err != nil {
return err
}
for _, p := range userPermissions {
o.UserPermissions = append(o.UserPermissions, &userPermissionValue{
UserID: p.UserID,
Value: p.Permission,
})
}
o.GroupPermissions = make([]*groupPermissionValue, 0)
groupPermissions, err := repo.permissionRepo.GetGroupPermissions(o.ID)
if err != nil {
return err
}
for _, p := range groupPermissions {
o.GroupPermissions = append(o.GroupPermissions, &groupPermissionValue{
GroupID: p.GroupID,
Value: p.Permission,
})
}
members, err := repo.GetMembers(o.ID)
if err != nil {
return nil
}
o.Members = make([]string, 0)
for _, u := range members {
o.Members = append(o.Members, u.GetID())
}
}
return nil
}

View File

@ -0,0 +1,102 @@
package repo
import (
"voltaserve/infra"
"gorm.io/gorm"
)
type UserPermission struct {
ID string `json:"id" gorm:"column:id"`
UserID string `json:"userId" gorm:"column:user_id"`
ResourceID string `json:"resourceId" gorm:"column:resource_id"`
Permission string `json:"permission" gorm:"column:permission"`
CreateTime string `json:"createTime" gorm:"column:create_time"`
}
type GroupPermission struct {
ID string `json:"id" gorm:"column:id"`
GroupID string `json:"groupId" gorm:"column:group_id"`
ResourceID string `json:"resourceId" gorm:"column:resource_id"`
Permission string `json:"permission" gorm:"column:permission"`
CreateTime string `json:"createTime" gorm:"column:create_time"`
}
type PermissionRepo interface {
GetUserPermissions(id string) ([]*UserPermission, error)
GetGroupPermissions(id string) ([]*GroupPermission, error)
}
func NewPermissionRepo() PermissionRepo {
return newPermissionRepo()
}
func (UserPermission) TableName() string {
return "userpermission"
}
func (GroupPermission) TableName() string {
return "grouppermission"
}
type userPermissionValue struct {
UserID string `json:"userId,omitempty"`
Value string `json:"value,omitempty"`
}
func (p userPermissionValue) GetUserID() string {
return p.UserID
}
func (p userPermissionValue) GetValue() string {
return p.Value
}
type groupPermissionValue struct {
GroupID string `json:"groupId,omitempty"`
Value string `json:"value,omitempty"`
}
func (p groupPermissionValue) GetGroupID() string {
return p.GroupID
}
func (p groupPermissionValue) GetValue() string {
return p.Value
}
type permissionRepo struct {
db *gorm.DB
}
func newPermissionRepo() *permissionRepo {
return &permissionRepo{
db: infra.GetDb(),
}
}
func (repo *permissionRepo) GetUserPermissions(id string) ([]*UserPermission, error) {
var res []*UserPermission
if db := repo.db.
Raw("SELECT * FROM userpermission WHERE resource_id = ?", id).
Scan(&res); db.Error != nil {
return nil, db.Error
}
if len(res) > 0 {
return res, nil
} else {
return []*UserPermission{}, nil
}
}
func (repo *permissionRepo) GetGroupPermissions(id string) ([]*GroupPermission, error) {
var res []*GroupPermission
if db := repo.db.
Raw("SELECT * FROM grouppermission WHERE resource_id = ?", id).
Scan(&res); db.Error != nil {
return nil, db.Error
}
if len(res) > 0 {
return res, nil
} else {
return []*GroupPermission{}, nil
}
}

View File

@ -0,0 +1,345 @@
package repo
import (
"encoding/json"
"errors"
"log"
"time"
"voltaserve/errorpkg"
"voltaserve/infra"
"voltaserve/model"
"gorm.io/datatypes"
"gorm.io/gorm"
)
type SnapshotUpdateOptions struct {
Original *model.S3Object
Preview *model.S3Object
Text *model.S3Object
Thumbnail *model.Thumbnail
Status string
}
type SnapshotRepo interface {
Find(id string) (model.Snapshot, error)
Save(snapshot model.Snapshot) error
Update(id string, opts SnapshotUpdateOptions) error
MapWithFile(id string, fileID string) error
DeleteMappingsForFile(fileID string) error
FindAllDangling() ([]model.Snapshot, error)
DeleteAllDangling() error
GetLatestVersionForFile(fileID string) (int64, error)
}
func NewSnapshotRepo() SnapshotRepo {
return newSnapshotRepo()
}
func NewSnapshot() model.Snapshot {
return &snapshotEntity{}
}
type snapshotEntity struct {
ID string `json:"id" gorm:"column:id;size:36"`
Version int64 `json:"version" gorm:"column:version"`
Original datatypes.JSON `json:"original,omitempty" gorm:"column:original"`
Preview datatypes.JSON `json:"preview,omitempty" gorm:"column:preview"`
Text datatypes.JSON `json:"text,omitempty" gorm:"column:text"`
Thumbnail datatypes.JSON `json:"thumbnail,omitempty" gorm:"column:thumbnail"`
Status string `json:"status,omitempty" gorm:"column,status"`
CreateTime string `json:"createTime" gorm:"column:create_time"`
UpdateTime *string `json:"updateTime,omitempty" gorm:"column:update_time"`
}
func (*snapshotEntity) TableName() string {
return "snapshot"
}
func (s *snapshotEntity) BeforeCreate(*gorm.DB) (err error) {
s.CreateTime = time.Now().UTC().Format(time.RFC3339)
return nil
}
func (s *snapshotEntity) BeforeSave(*gorm.DB) (err error) {
timeNow := time.Now().UTC().Format(time.RFC3339)
s.UpdateTime = &timeNow
return nil
}
func (s *snapshotEntity) GetID() string {
return s.ID
}
func (s *snapshotEntity) GetVersion() int64 {
return s.Version
}
func (s *snapshotEntity) GetOriginal() *model.S3Object {
if s.Original.String() == "" {
return nil
}
var res = model.S3Object{}
if err := json.Unmarshal([]byte(s.Original.String()), &res); err != nil {
log.Fatal(err)
return nil
}
return &res
}
func (s *snapshotEntity) GetPreview() *model.S3Object {
if s.Preview.String() == "" {
return nil
}
var res = model.S3Object{}
if err := json.Unmarshal([]byte(s.Preview.String()), &res); err != nil {
log.Fatal(err)
return nil
}
return &res
}
func (s *snapshotEntity) GetText() *model.S3Object {
if s.Text.String() == "" {
return nil
}
var res = model.S3Object{}
if err := json.Unmarshal([]byte(s.Text.String()), &res); err != nil {
log.Fatal(err)
return nil
}
return &res
}
func (s *snapshotEntity) GetThumbnail() *model.Thumbnail {
if s.Thumbnail.String() == "" {
return nil
}
var res = model.Thumbnail{}
if err := json.Unmarshal([]byte(s.Thumbnail.String()), &res); err != nil {
log.Fatal(err)
return nil
}
return &res
}
func (s *snapshotEntity) GetStatus() string {
return s.Status
}
func (s *snapshotEntity) SetID(id string) {
s.ID = id
}
func (s *snapshotEntity) SetVersion(version int64) {
s.Version = version
}
func (s *snapshotEntity) SetOriginal(m *model.S3Object) {
if m == nil {
s.Original = nil
} else {
b, err := json.Marshal(m)
if err != nil {
log.Fatal(err)
return
}
if err := s.Original.UnmarshalJSON(b); err != nil {
log.Fatal(err)
}
}
}
func (s *snapshotEntity) SetPreview(m *model.S3Object) {
if m == nil {
s.Preview = nil
} else {
b, err := json.Marshal(m)
if err != nil {
log.Fatal(err)
return
}
if err := s.Preview.UnmarshalJSON(b); err != nil {
log.Fatal(err)
}
}
}
func (s *snapshotEntity) SetText(m *model.S3Object) {
if m == nil {
s.Text = nil
} else {
b, err := json.Marshal(m)
if err != nil {
log.Fatal(err)
return
}
if err := s.Text.UnmarshalJSON(b); err != nil {
log.Fatal(err)
}
}
}
func (s *snapshotEntity) SetThumbnail(m *model.Thumbnail) {
if m == nil {
s.Thumbnail = nil
} else {
b, err := json.Marshal(m)
if err != nil {
log.Fatal(err)
return
}
if err := s.Thumbnail.UnmarshalJSON(b); err != nil {
log.Fatal(err)
}
}
}
func (s *snapshotEntity) SetStatus(status string) {
s.Status = status
}
func (s *snapshotEntity) HasOriginal() bool {
return s.Original != nil
}
func (s *snapshotEntity) HasPreview() bool {
return s.Preview != nil
}
func (s *snapshotEntity) HasText() bool {
return s.Text != nil
}
func (s *snapshotEntity) HasThumbnail() bool {
return s.Thumbnail != nil
}
func (s *snapshotEntity) GetCreateTime() string {
return s.CreateTime
}
func (s *snapshotEntity) GetUpdateTime() *string {
return s.UpdateTime
}
type snapshotRepo struct {
db *gorm.DB
}
func newSnapshotRepo() *snapshotRepo {
return &snapshotRepo{
db: infra.GetDb(),
}
}
func (repo *snapshotRepo) find(id string) (*snapshotEntity, error) {
var res snapshotEntity
if db := repo.db.Where("id = ?", id).First(&res); db.Error != nil {
if errors.Is(db.Error, gorm.ErrRecordNotFound) {
return nil, errorpkg.NewSnapshotNotFoundError(db.Error)
} else {
return nil, errorpkg.NewInternalServerError(db.Error)
}
}
return &res, nil
}
func (repo *snapshotRepo) Find(id string) (model.Snapshot, error) {
res, err := repo.find(id)
if err != nil {
return nil, err
}
return res, nil
}
func (repo *snapshotRepo) Save(snapshot model.Snapshot) error {
if db := repo.db.Save(snapshot); db.Error != nil {
return db.Error
}
return nil
}
func (repo *snapshotRepo) Update(id string, opts SnapshotUpdateOptions) error {
snapshot, err := repo.find(id)
if err != nil {
return err
}
if opts.Thumbnail != nil {
snapshot.SetThumbnail(opts.Thumbnail)
}
if opts.Original != nil {
snapshot.SetOriginal(opts.Original)
}
if opts.Preview != nil {
snapshot.SetPreview(opts.Preview)
}
if opts.Text != nil {
snapshot.SetText(opts.Text)
}
if opts.Status != "" {
snapshot.SetStatus(opts.Status)
}
if db := repo.db.Save(&snapshot); db.Error != nil {
return db.Error
}
return nil
}
func (repo *snapshotRepo) MapWithFile(id string, fileID string) error {
if db := repo.db.Exec("INSERT INTO snapshot_file (snapshot_id, file_id) VALUES (?, ?)", id, fileID); db.Error != nil {
return db.Error
}
return nil
}
func (repo *snapshotRepo) DeleteMappingsForFile(fileID string) error {
if db := repo.db.Exec("DELETE FROM snapshot_file WHERE file_id = ?", fileID); db.Error != nil {
return db.Error
}
return nil
}
func (repo *snapshotRepo) findAllForFile(fileID string) ([]*snapshotEntity, error) {
var res []*snapshotEntity
db := repo.db.
Raw("SELECT * FROM snapshot s LEFT JOIN snapshot_file sf ON s.id = sf.snapshot_id WHERE sf.file_id = ? ORDER BY s.version", fileID).
Scan(&res)
if db.Error != nil {
return nil, db.Error
}
return res, nil
}
func (repo *snapshotRepo) FindAllDangling() ([]model.Snapshot, error) {
var snapshots []*snapshotEntity
db := repo.db.Raw("SELECT * FROM snapshot s LEFT JOIN snapshot_file sf ON s.id = sf.snapshot_id WHERE sf.snapshot_id IS NULL").Scan(&snapshots)
if db.Error != nil {
return nil, db.Error
}
var res []model.Snapshot
for _, s := range snapshots {
res = append(res, s)
}
return res, nil
}
func (repo *snapshotRepo) DeleteAllDangling() error {
if db := repo.db.Exec("DELETE FROM snapshot WHERE id IN (SELECT s.id FROM (SELECT * FROM snapshot) s LEFT JOIN snapshot_file sf ON s.id = sf.snapshot_id WHERE sf.snapshot_id IS NULL)"); db.Error != nil {
return db.Error
}
return nil
}
func (repo *snapshotRepo) GetLatestVersionForFile(fileID string) (int64, error) {
type Result struct {
Result int64
}
var res Result
if db := repo.db.
Raw("SELECT coalesce(max(s.version), 0) + 1 result FROM snapshot s LEFT JOIN snapshot_file map ON s.id = map.snapshot_id WHERE map.file_id = ?", fileID).
Scan(&res); db.Error != nil {
return 0, db.Error
}
return res.Result, nil
}

View File

@ -0,0 +1,121 @@
package repo
import (
"errors"
"voltaserve/errorpkg"
"voltaserve/infra"
"voltaserve/model"
"gorm.io/gorm"
)
type UserRepo interface {
Find(id string) (model.User, error)
FindByEmail(email string) (model.User, error)
FindAll() ([]model.User, error)
}
func NewUserRepo() UserRepo {
return newUserRepo()
}
func NewUser() model.User {
return &userEntity{}
}
type userEntity struct {
ID string `json:"id" gorm:"column:id"`
FullName string `json:"fullName" gorm:"column:full_name"`
Username string `json:"username" gorm:"column:username"`
Email string `json:"email" gorm:"column:email"`
Picture *string `json:"picture" gorm:"column:picture"`
IsEmailConfirmed bool `json:"isEmailConfirmed" gorm:"column:is_email_confirmed"`
PasswordHash string `json:"passwordHash" gorm:"column:password_hash"`
RefreshTokenValue *string `json:"refreshTokenValue" gorm:"column:refresh_token_value"`
RefreshTokenValidTo *int64 `json:"refreshTokenValidTo" gorm:"column:refresh_token_valid_to"`
ResetPasswordToken *string `json:"resetPasswordToken" gorm:"column:reset_password_token"`
EmailConfirmationToken *string `json:"emailConfirmationToken" gorm:"column:email_confirmation_token"`
CreateTime string `json:"createTime" gorm:"column:create_time"`
UpdateTime *string `json:"updateTime" gorm:"column:update_time"`
}
func (userEntity) TableName() string {
return "user"
}
func (u userEntity) GetID() string {
return u.ID
}
func (u userEntity) GetFullName() string {
return u.FullName
}
func (u userEntity) GetUsername() string {
return u.Username
}
func (u userEntity) GetEmail() string {
return u.Email
}
func (u userEntity) GetPicture() *string {
return u.Picture
}
func (u userEntity) GetIsEmailConfirmed() bool {
return u.IsEmailConfirmed
}
func (u userEntity) GetCreateTime() string {
return u.CreateTime
}
func (u userEntity) GetUpdateTime() *string {
return u.UpdateTime
}
type userRepo struct {
db *gorm.DB
}
func newUserRepo() *userRepo {
return &userRepo{
db: infra.GetDb(),
}
}
func (repo *userRepo) Find(id string) (model.User, error) {
var res = userEntity{}
db := repo.db.Where("id = ?", id).First(&res)
if db.Error != nil {
if errors.Is(db.Error, gorm.ErrRecordNotFound) {
return nil, errorpkg.NewUserNotFoundError(db.Error)
} else {
return nil, errorpkg.NewInternalServerError(db.Error)
}
}
return &res, nil
}
func (repo *userRepo) FindByEmail(email string) (model.User, error) {
var res = userEntity{}
db := repo.db.Where("email = ?", email).First(&res)
if db.Error != nil {
return nil, db.Error
}
return &res, nil
}
func (repo *userRepo) FindAll() ([]model.User, error) {
var entities []*userEntity
db := repo.db.Raw(`select * from "user"`).Scan(&entities)
if db.Error != nil {
return nil, db.Error
}
var res []model.User
for _, u := range entities {
res = append(res, u)
}
return res, nil
}

View File

@ -0,0 +1,319 @@
package repo
import (
"errors"
"time"
"voltaserve/errorpkg"
"voltaserve/helper"
"voltaserve/infra"
"voltaserve/model"
"gorm.io/gorm"
)
type WorkspaceInsertOptions struct {
ID string
Name string
StorageCapacity int64
Image *string
OrganizationID string
RootID string
Bucket string
}
type WorkspaceRepo interface {
Insert(opts WorkspaceInsertOptions) (model.Workspace, error)
Find(id string) (model.Workspace, error)
UpdateName(id string, name string) (model.Workspace, error)
UpdateStorageCapacity(id string, storageCapacity int64) (model.Workspace, error)
UpdateRootID(id string, rootNodeID string) error
Delete(id string) error
GetIDs() ([]string, error)
GetIDsByOrganization(orgID string) ([]string, error)
GrantUserPermission(id string, userID string, permission string) error
}
func NewWorkspaceRepo() WorkspaceRepo {
return newWorkspaceRepo()
}
func NewWorkspace() model.Workspace {
return &workspaceEntity{}
}
type workspaceEntity struct {
ID string `json:"id," gorm:"column:id;size:36"`
Name string `json:"name" gorm:"column:name;size:255"`
StorageCapacity int64 `json:"storageCapacity" gorm:"column:storage_capacity"`
RootID string `json:"rootId" gorm:"column:root_id;size:36"`
OrganizationID string `json:"organizationId" gorm:"column:organization_id;size:36"`
UserPermissions []*userPermissionValue `json:"userPermissions" gorm:"-"`
GroupPermissions []*groupPermissionValue `json:"groupPermissions" gorm:"-"`
Bucket string `json:"bucket" gorm:"column:bucket;size:255"`
CreateTime string `json:"createTime" gorm:"column:create_time"`
UpdateTime *string `json:"updateTime,omitempty" gorm:"column:update_time"`
}
func (*workspaceEntity) TableName() string {
return "workspace"
}
func (w *workspaceEntity) BeforeCreate(*gorm.DB) (err error) {
w.CreateTime = time.Now().UTC().Format(time.RFC3339)
return nil
}
func (w *workspaceEntity) BeforeSave(*gorm.DB) (err error) {
timeNow := time.Now().UTC().Format(time.RFC3339)
w.UpdateTime = &timeNow
return nil
}
func (w *workspaceEntity) GetID() string {
return w.ID
}
func (w *workspaceEntity) GetName() string {
return w.Name
}
func (w *workspaceEntity) GetStorageCapacity() int64 {
return w.StorageCapacity
}
func (w *workspaceEntity) GetRootID() string {
return w.RootID
}
func (w *workspaceEntity) GetOrganizationID() string {
return w.OrganizationID
}
func (w *workspaceEntity) GetUserPermissions() []model.CoreUserPermission {
var res []model.CoreUserPermission
for _, p := range w.UserPermissions {
res = append(res, p)
}
return res
}
func (w *workspaceEntity) GetGroupPermissions() []model.CoreGroupPermission {
var res []model.CoreGroupPermission
for _, p := range w.GroupPermissions {
res = append(res, p)
}
return res
}
func (w *workspaceEntity) GetBucket() string {
return w.Bucket
}
func (w *workspaceEntity) GetCreateTime() string {
return w.CreateTime
}
func (w *workspaceEntity) GetUpdateTime() *string {
return w.UpdateTime
}
func (w *workspaceEntity) SetName(name string) {
w.Name = name
}
func (w *workspaceEntity) SetUpdateTime(updateTime *string) {
w.UpdateTime = updateTime
}
type workspaceRepo struct {
db *gorm.DB
permissionRepo *permissionRepo
}
func newWorkspaceRepo() *workspaceRepo {
return &workspaceRepo{
db: infra.GetDb(),
permissionRepo: newPermissionRepo(),
}
}
func (repo *workspaceRepo) Insert(opts WorkspaceInsertOptions) (model.Workspace, error) {
var id string
if len(opts.ID) > 0 {
id = opts.ID
} else {
id = helper.NewID()
}
workspace := workspaceEntity{
ID: id,
Name: opts.Name,
StorageCapacity: opts.StorageCapacity,
RootID: opts.RootID,
OrganizationID: opts.OrganizationID,
Bucket: opts.Bucket,
}
if db := repo.db.Save(&workspace); db.Error != nil {
return nil, db.Error
}
res, err := repo.find(id)
if err != nil {
return nil, err
}
if err := repo.populateModelFields([]*workspaceEntity{res}); err != nil {
return nil, err
}
return res, nil
}
func (repo *workspaceRepo) find(id string) (*workspaceEntity, error) {
var res = workspaceEntity{}
db := repo.db.Where("id = ?", id).First(&res)
if db.Error != nil {
if errors.Is(db.Error, gorm.ErrRecordNotFound) {
return nil, errorpkg.NewWorkspaceNotFoundError(db.Error)
} else {
return nil, errorpkg.NewInternalServerError(db.Error)
}
}
return &res, nil
}
func (repo *workspaceRepo) Find(id string) (model.Workspace, error) {
workspace, err := repo.find(id)
if err != nil {
return nil, err
}
if err := repo.populateModelFields([]*workspaceEntity{workspace}); err != nil {
return nil, err
}
return workspace, err
}
func (repo *workspaceRepo) UpdateName(id string, name string) (model.Workspace, error) {
workspace, err := repo.find(id)
if err != nil {
return &workspaceEntity{}, err
}
workspace.Name = name
if db := repo.db.Save(&workspace); db.Error != nil {
return nil, db.Error
}
res, err := repo.Find(id)
if err != nil {
return nil, err
}
return res, nil
}
func (repo *workspaceRepo) UpdateStorageCapacity(id string, storageCapacity int64) (model.Workspace, error) {
workspace, err := repo.find(id)
if err != nil {
return &workspaceEntity{}, err
}
workspace.StorageCapacity = storageCapacity
db := repo.db.Save(&workspace)
if db.Error != nil {
return nil, db.Error
}
res, err := repo.Find(id)
if err != nil {
return nil, err
}
return res, nil
}
func (repo *workspaceRepo) UpdateRootID(id string, rootNodeID string) error {
db := repo.db.Exec("UPDATE workspace SET root_id = ? WHERE id = ?", rootNodeID, id)
if db.Error != nil {
return db.Error
}
return nil
}
func (repo *workspaceRepo) Delete(id string) error {
db := repo.db.Exec("DELETE FROM workspace WHERE id = ?", id)
if db.Error != nil {
return db.Error
}
db = repo.db.Exec("DELETE FROM userpermission WHERE resource_id = ?", id)
if db.Error != nil {
return db.Error
}
db = repo.db.Exec("DELETE FROM grouppermission WHERE resource_id = ?", id)
if db.Error != nil {
return db.Error
}
return nil
}
func (repo *workspaceRepo) GetIDs() ([]string, error) {
type IDResult struct {
Result string
}
var ids []IDResult
db := repo.db.Raw("SELECT id result FROM workspace ORDER BY create_time DESC").Scan(&ids)
if db.Error != nil {
return []string{}, db.Error
}
res := []string{}
for _, id := range ids {
res = append(res, id.Result)
}
return res, nil
}
func (repo *workspaceRepo) GetIDsByOrganization(orgID string) ([]string, error) {
type IDResult struct {
Result string
}
var ids []IDResult
db := repo.db.
Raw("SELECT id result FROM workspace WHERE organization_id = ? ORDER BY create_time DESC", orgID).
Scan(&ids)
if db.Error != nil {
return nil, db.Error
}
res := []string{}
for _, id := range ids {
res = append(res, id.Result)
}
return res, nil
}
func (repo *workspaceRepo) GrantUserPermission(id string, userID string, permission string) error {
db := repo.db.Exec(
"INSERT INTO userpermission (id, user_id, resource_id, permission) VALUES (?, ?, ?, ?) ON CONFLICT (user_id, resource_id) DO UPDATE SET permission = ?",
helper.NewID(), userID, id, permission, permission)
if db.Error != nil {
return db.Error
}
return nil
}
func (repo *workspaceRepo) populateModelFields(workspaces []*workspaceEntity) error {
for _, w := range workspaces {
w.UserPermissions = make([]*userPermissionValue, 0)
userPermissions, err := repo.permissionRepo.GetUserPermissions(w.ID)
if err != nil {
return err
}
for _, p := range userPermissions {
w.UserPermissions = append(w.UserPermissions, &userPermissionValue{
UserID: p.UserID,
Value: p.Permission,
})
}
w.GroupPermissions = make([]*groupPermissionValue, 0)
groupPermissions, err := repo.permissionRepo.GetGroupPermissions(w.ID)
if err != nil {
return err
}
for _, p := range groupPermissions {
w.GroupPermissions = append(w.GroupPermissions, &groupPermissionValue{
GroupID: p.GroupID,
Value: p.Permission,
})
}
}
return nil
}