shareEntry.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. package shareEntry
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "log"
  6. "path/filepath"
  7. "strings"
  8. "sync"
  9. "imuslab.com/arozos/mod/database"
  10. fs "imuslab.com/arozos/mod/filesystem"
  11. )
  12. /*
  13. Share Entry
  14. This module is designed to isolate the entry operatiosn with the
  15. handle operations so as to reduce the complexity of recursive import
  16. during development
  17. */
  18. type ShareEntryTable struct {
  19. FileToUrlMap *sync.Map
  20. UrlToFileMap *sync.Map
  21. Database *database.Database
  22. }
  23. type ShareOption struct {
  24. UUID string
  25. FileRealPath string
  26. Owner string
  27. Accessibles []string //Use to store username or group names if permission is groups or users
  28. Permission string //Access permission, allow {anyone / signedin / samegroup / groups / users}
  29. AllowLivePreview bool
  30. }
  31. func NewShareEntryTable(db *database.Database) *ShareEntryTable {
  32. //Create the share table if not exists
  33. db.NewTable("share")
  34. FileToUrlMap := sync.Map{}
  35. UrlToFileMap := sync.Map{}
  36. //Load the old share links
  37. entries, _ := db.ListTable("share")
  38. for _, keypairs := range entries {
  39. shareObject := new(ShareOption)
  40. json.Unmarshal(keypairs[1], &shareObject)
  41. if shareObject != nil {
  42. //Append this to the maps
  43. FileToUrlMap.Store(shareObject.FileRealPath, shareObject)
  44. UrlToFileMap.Store(shareObject.UUID, shareObject)
  45. }
  46. }
  47. return &ShareEntryTable{
  48. FileToUrlMap: &FileToUrlMap,
  49. UrlToFileMap: &UrlToFileMap,
  50. Database: db,
  51. }
  52. }
  53. //Delete the share on this vpath
  54. func (s *ShareEntryTable) DeleteShare(rpath string) error {
  55. //Check if the share already exists. If yes, use the previous link
  56. val, ok := s.FileToUrlMap.Load(rpath)
  57. if ok {
  58. //Exists. Send back the old share url
  59. uuid := val.(*ShareOption).UUID
  60. //Remove this from the database
  61. err := s.Database.Delete("share", uuid)
  62. if err != nil {
  63. return err
  64. }
  65. //Remove this form the current sync map
  66. s.UrlToFileMap.Delete(uuid)
  67. s.FileToUrlMap.Delete(rpath)
  68. return nil
  69. } else {
  70. //Already deleted from buffered record.
  71. return nil
  72. }
  73. }
  74. func (s *ShareEntryTable) GetShareUUIDFromPath(rpath string) string {
  75. targetShareObject := s.GetShareObjectFromRealPath(rpath)
  76. if (targetShareObject) != nil {
  77. return targetShareObject.UUID
  78. }
  79. return ""
  80. }
  81. func (s *ShareEntryTable) GetShareObjectFromRealPath(rpath string) *ShareOption {
  82. rpath = filepath.ToSlash(filepath.Clean(rpath))
  83. var targetShareOption *ShareOption
  84. s.FileToUrlMap.Range(func(k, v interface{}) bool {
  85. filePath := k.(string)
  86. shareObject := v.(*ShareOption)
  87. if filepath.ToSlash(filepath.Clean(filePath)) == rpath {
  88. targetShareOption = shareObject
  89. }
  90. return true
  91. })
  92. return targetShareOption
  93. }
  94. func (s *ShareEntryTable) GetShareObjectFromUUID(uuid string) *ShareOption {
  95. var targetShareOption *ShareOption
  96. s.UrlToFileMap.Range(func(k, v interface{}) bool {
  97. thisUuid := k.(string)
  98. shareObject := v.(*ShareOption)
  99. if thisUuid == uuid {
  100. targetShareOption = shareObject
  101. }
  102. return true
  103. })
  104. return targetShareOption
  105. }
  106. func (s *ShareEntryTable) FileIsShared(rpath string) bool {
  107. shareUUID := s.GetShareUUIDFromPath(rpath)
  108. return shareUUID != ""
  109. }
  110. func (s *ShareEntryTable) RemoveShareByRealpath(rpath string) error {
  111. so, ok := s.FileToUrlMap.Load(rpath)
  112. if ok {
  113. shareUUID := so.(*ShareOption).UUID
  114. s.UrlToFileMap.Delete(shareUUID)
  115. s.FileToUrlMap.Delete(rpath)
  116. s.Database.Delete("share", shareUUID)
  117. } else {
  118. return errors.New("Share with given realpath not exists")
  119. }
  120. return nil
  121. }
  122. func (s *ShareEntryTable) RemoveShareByUUID(uuid string) error {
  123. so, ok := s.UrlToFileMap.Load(uuid)
  124. if ok {
  125. s.FileToUrlMap.Delete(so.(*ShareOption).FileRealPath)
  126. s.UrlToFileMap.Delete(uuid)
  127. s.Database.Delete("share", uuid)
  128. } else {
  129. return errors.New("Share with given uuid not exists")
  130. }
  131. return nil
  132. }
  133. func (s *ShareEntryTable) ResolveShareVrootPath(subpath string, username string, usergroup []string) (string, error) {
  134. //Get a list of accessible files from this user
  135. subpathElements := strings.Split(filepath.ToSlash(filepath.Clean(subpath))[1:], "/")
  136. if len(subpathElements) == 0 {
  137. //Requesting root folder.
  138. return "", errors.New("This virtual file system router do not support root listing")
  139. }
  140. //Analysis the subpath elements
  141. if len(subpathElements) == 1 {
  142. return "", errors.New("Redirect: parent")
  143. } else if len(subpathElements) == 2 {
  144. //ID only or ID with the target filename
  145. shareObject := s.GetShareObjectFromUUID(subpathElements[0])
  146. if shareObject == nil {
  147. return "", errors.New("Share file not found")
  148. }
  149. return shareObject.FileRealPath, nil
  150. } else if len(subpathElements) > 2 {
  151. //Loading folder / files inside folder type shares
  152. shareObject := s.GetShareObjectFromUUID(subpathElements[0])
  153. folderSubpaths := append([]string{shareObject.FileRealPath}, subpathElements[2:]...)
  154. targetFolder := filepath.Join(folderSubpaths...)
  155. log.Println("Loading folder:", targetFolder)
  156. return targetFolder, nil
  157. }
  158. return "", errors.New("Not implemented")
  159. }
  160. func (s *ShareEntryTable) RouteShareVroot(subpath string, username string, usergroup []string) ([]fs.FileData, error) {
  161. if subpath == "" {
  162. return s.listRootForUser(username, usergroup), nil
  163. } else {
  164. log.Println("Checkpoint!", subpath)
  165. return []fs.FileData{}, nil
  166. }
  167. }
  168. func (s *ShareEntryTable) listRootForUser(username string, usergroup []string) []fs.FileData {
  169. //Iterate through all shares in the system to see which of the share is user accessible
  170. userAccessiableShare := []*ShareOption{}
  171. s.FileToUrlMap.Range(func(fp, so interface{}) bool {
  172. fileRealpath := fp.(string)
  173. thisShareOption := so.(*ShareOption)
  174. if fs.FileExists(fileRealpath) {
  175. //File exists. Check if the share options allow this user access (Only signed in user has username)
  176. if thisShareOption.Permission == "anyone" || thisShareOption.Permission == "signedin" {
  177. userAccessiableShare = append(userAccessiableShare, thisShareOption)
  178. } else if thisShareOption.Permission == "samegroup" || thisShareOption.Permission == "groups" {
  179. for _, thisUserGroup := range usergroup {
  180. if stringInSlice(thisUserGroup, thisShareOption.Accessibles) {
  181. //User's group is in the allowed group
  182. userAccessiableShare = append(userAccessiableShare, thisShareOption)
  183. break
  184. }
  185. }
  186. } else if thisShareOption.Permission == "users" {
  187. if stringInSlice(username, thisShareOption.Accessibles) {
  188. //User's group is in the allowed group
  189. userAccessiableShare = append(userAccessiableShare, thisShareOption)
  190. }
  191. }
  192. }
  193. return true
  194. })
  195. results := []fs.FileData{}
  196. for _, thisShareObject := range userAccessiableShare {
  197. rpath := thisShareObject.FileRealPath
  198. thisFile := fs.GetFileDataFromPath("share:/"+thisShareObject.UUID+"/"+filepath.Base(rpath), rpath, 2)
  199. thisFile.IsShared = true
  200. results = append(results, thisFile)
  201. }
  202. return results
  203. }