desktop.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757
  1. package main
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "log"
  6. "net/http"
  7. "os"
  8. "path/filepath"
  9. "strconv"
  10. "strings"
  11. fs "imuslab.com/arozos/mod/filesystem"
  12. "imuslab.com/arozos/mod/filesystem/arozfs"
  13. "imuslab.com/arozos/mod/filesystem/shortcut"
  14. module "imuslab.com/arozos/mod/modules"
  15. prout "imuslab.com/arozos/mod/prouter"
  16. "imuslab.com/arozos/mod/utils"
  17. )
  18. // Desktop script initiation
  19. func DesktopInit() {
  20. systemWideLogger.PrintAndLog("Desktop", "Starting Desktop Services", nil)
  21. router := prout.NewModuleRouter(prout.RouterOption{
  22. ModuleName: "Desktop",
  23. AdminOnly: false,
  24. UserHandler: userHandler,
  25. DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
  26. utils.SendErrorResponse(w, "Permission Denied")
  27. },
  28. })
  29. //Register all the required API
  30. router.HandleFunc("/system/desktop/listDesktop", desktop_listFiles)
  31. router.HandleFunc("/system/desktop/theme", desktop_theme_handler)
  32. router.HandleFunc("/system/desktop/files", desktop_fileLocation_handler)
  33. router.HandleFunc("/system/desktop/host", desktop_hostdetailHandler)
  34. router.HandleFunc("/system/desktop/user", desktop_handleUserInfo)
  35. router.HandleFunc("/system/desktop/preference", desktop_preference_handler)
  36. router.HandleFunc("/system/desktop/createShortcut", desktop_shortcutHandler)
  37. //API related to desktop based operations
  38. router.HandleFunc("/system/desktop/opr/renameShortcut", desktop_handleShortcutRename)
  39. //Initialize desktop database
  40. err := sysdb.NewTable("desktop")
  41. if err != nil {
  42. log.Println("Unable to create database table for Desktop. Please validation your installation.")
  43. log.Fatal(err)
  44. os.Exit(1)
  45. }
  46. //Register Desktop Module
  47. moduleHandler.RegisterModule(module.ModuleInfo{
  48. Name: "Desktop",
  49. Desc: "The Web Desktop experience for everyone",
  50. Group: "Interface Module",
  51. IconPath: "img/desktop/desktop.png",
  52. Version: internal_version,
  53. StartDir: "",
  54. SupportFW: false,
  55. LaunchFWDir: "",
  56. SupportEmb: false,
  57. })
  58. }
  59. /*
  60. FUNCTIONS RELATED TO PARSING DESKTOP FILE ICONS
  61. The functions in this section handle file listing and its icon locations.
  62. */
  63. func desktop_initUserFolderStructure(username string) {
  64. //Call to filesystem for creating user file struture at root dir
  65. userinfo, _ := userHandler.GetUserInfoFromUsername(username)
  66. userfsh, err := userinfo.GetHomeFileSystemHandler()
  67. if err != nil {
  68. systemWideLogger.PrintAndLog("Desktop", "Unable to initiate user desktop folder", err)
  69. return
  70. }
  71. userFsa := userfsh.FileSystemAbstraction
  72. userDesktopPath, _ := userFsa.VirtualPathToRealPath("user:/Desktop", userinfo.Username)
  73. if !userFsa.FileExists(userDesktopPath) {
  74. //Desktop directory not exists. Create one and copy a template desktop
  75. userFsa.MkdirAll(userDesktopPath, 0755)
  76. //Copy template file from system folder if exists
  77. templateFolder := "./system/desktop/template/"
  78. if fs.FileExists(templateFolder) {
  79. templateFiles, _ := filepath.Glob(templateFolder + "*")
  80. for _, tfile := range templateFiles {
  81. input, _ := os.ReadFile(tfile)
  82. userFsa.WriteFile(arozfs.ToSlash(filepath.Join(userDesktopPath, filepath.Base(tfile))), input, 0755)
  83. }
  84. }
  85. }
  86. }
  87. // Return the information about the host
  88. func desktop_hostdetailHandler(w http.ResponseWriter, r *http.Request) {
  89. type returnStruct struct {
  90. Hostname string
  91. DeviceUUID string
  92. BuildVersion string
  93. InternalVersion string
  94. DeviceVendor string
  95. DeviceModel string
  96. }
  97. jsonString, _ := json.Marshal(returnStruct{
  98. Hostname: *host_name,
  99. DeviceUUID: deviceUUID,
  100. BuildVersion: build_version,
  101. InternalVersion: internal_version,
  102. DeviceVendor: deviceVendor,
  103. DeviceModel: deviceModel,
  104. })
  105. utils.SendJSONResponse(w, string(jsonString))
  106. }
  107. func desktop_handleShortcutRename(w http.ResponseWriter, r *http.Request) {
  108. //Check if the user directory already exists
  109. userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
  110. if err != nil {
  111. utils.SendErrorResponse(w, "User not logged in")
  112. return
  113. }
  114. //Get the shortcut file that is renaming
  115. target, err := utils.GetPara(r, "src")
  116. if err != nil {
  117. utils.SendErrorResponse(w, "Invalid shortcut file path given")
  118. return
  119. }
  120. //Get the new name
  121. new, err := utils.GetPara(r, "new")
  122. if err != nil {
  123. utils.SendErrorResponse(w, "Invalid new name given")
  124. return
  125. }
  126. fsh, subpath, _ := GetFSHandlerSubpathFromVpath(target)
  127. fshAbs := fsh.FileSystemAbstraction
  128. //Check if the file actually exists and it is on desktop
  129. rpath, err := fshAbs.VirtualPathToRealPath(subpath, userinfo.Username)
  130. if err != nil {
  131. utils.SendErrorResponse(w, err.Error())
  132. return
  133. }
  134. if target[:14] != "user:/Desktop/" {
  135. utils.SendErrorResponse(w, "Shortcut not on desktop")
  136. return
  137. }
  138. if !fshAbs.FileExists(rpath) {
  139. utils.SendErrorResponse(w, "File not exists")
  140. return
  141. }
  142. //OK. Change the name of the shortcut
  143. originalShortcut, err := fshAbs.ReadFile(rpath)
  144. if err != nil {
  145. utils.SendErrorResponse(w, "Shortcut file read failed")
  146. return
  147. }
  148. lines := strings.Split(string(originalShortcut), "\n")
  149. if len(lines) < 4 {
  150. //Invalid shortcut properties
  151. utils.SendErrorResponse(w, "Invalid shortcut file")
  152. return
  153. }
  154. //Change the 2nd line to the new name
  155. lines[1] = new
  156. newShortcutContent := strings.Join(lines, "\n")
  157. err = fshAbs.WriteFile(rpath, []byte(newShortcutContent), 0755)
  158. if err != nil {
  159. utils.SendErrorResponse(w, err.Error())
  160. return
  161. }
  162. utils.SendOK(w)
  163. }
  164. func desktop_listFiles(w http.ResponseWriter, r *http.Request) {
  165. //Check if the user directory already exists
  166. userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
  167. if err != nil {
  168. utils.SendErrorResponse(w, "user not logged in!")
  169. return
  170. }
  171. username := userinfo.Username
  172. //Initiate the user folder structure. Do nothing if the structure already exists.
  173. desktop_initUserFolderStructure(username)
  174. //List all files inside the user desktop directory
  175. fsh, subpath, err := GetFSHandlerSubpathFromVpath("user:/Desktop/")
  176. if err != nil {
  177. utils.SendErrorResponse(w, "Desktop file load failed")
  178. return
  179. }
  180. fshAbs := fsh.FileSystemAbstraction
  181. userDesktopRealpath, err := fshAbs.VirtualPathToRealPath(subpath, userinfo.Username)
  182. if err != nil {
  183. utils.SendErrorResponse(w, err.Error())
  184. return
  185. }
  186. files, err := fshAbs.Glob(userDesktopRealpath + "/*")
  187. if err != nil {
  188. utils.SendErrorResponse(w, "Desktop file load failed")
  189. return
  190. }
  191. //Desktop object structure
  192. type desktopObject struct {
  193. Filepath string
  194. Filename string
  195. Ext string
  196. IsDir bool
  197. IsEmptyDir bool
  198. IsShortcut bool
  199. IsShared bool
  200. ShortcutImage string
  201. ShortcutType string
  202. ShortcutName string
  203. ShortcutPath string
  204. IconX int
  205. IconY int
  206. }
  207. desktopFiles := []desktopObject{}
  208. for _, this := range files {
  209. //Always use linux convension for directory seperator
  210. if filepath.Base(this)[:1] == "." {
  211. //Skipping hidden files
  212. continue
  213. }
  214. this = filepath.ToSlash(this)
  215. thisFileObject := new(desktopObject)
  216. thisFileObject.Filepath, _ = fshAbs.RealPathToVirtualPath(this, userinfo.Username)
  217. thisFileObject.Filename = filepath.Base(this)
  218. thisFileObject.Ext = filepath.Ext(this)
  219. thisFileObject.IsDir = fshAbs.IsDir(this)
  220. if thisFileObject.IsDir {
  221. //Check if this dir is empty
  222. filesInFolder, _ := fshAbs.Glob(filepath.ToSlash(filepath.Clean(this)) + "/*")
  223. fc := 0
  224. for _, f := range filesInFolder {
  225. if filepath.Base(f)[:1] != "." {
  226. fc++
  227. }
  228. }
  229. if fc > 0 {
  230. thisFileObject.IsEmptyDir = false
  231. } else {
  232. thisFileObject.IsEmptyDir = true
  233. }
  234. } else {
  235. //File object. Default true
  236. thisFileObject.IsEmptyDir = true
  237. }
  238. //Check if the file is a shortcut
  239. isShortcut := false
  240. if filepath.Ext(this) == ".shortcut" {
  241. isShortcut = true
  242. shortcutInfo, _ := fshAbs.ReadFile(this)
  243. infoSegments := strings.Split(strings.ReplaceAll(string(shortcutInfo), "\r\n", "\n"), "\n")
  244. if len(infoSegments) < 4 {
  245. thisFileObject.ShortcutType = "invalid"
  246. } else {
  247. thisFileObject.ShortcutType = infoSegments[0]
  248. thisFileObject.ShortcutName = infoSegments[1]
  249. thisFileObject.ShortcutPath = infoSegments[2]
  250. thisFileObject.ShortcutImage = infoSegments[3]
  251. }
  252. }
  253. thisFileObject.IsShortcut = isShortcut
  254. //Check if this file is shared
  255. thisFileObject.IsShared = shareManager.FileIsShared(userinfo, this)
  256. //Check the file location
  257. username, _ := authAgent.GetUserName(w, r)
  258. x, y, _ := getDesktopLocatioFromPath(thisFileObject.Filename, username)
  259. //This file already have a location on desktop
  260. thisFileObject.IconX = x
  261. thisFileObject.IconY = y
  262. desktopFiles = append(desktopFiles, *thisFileObject)
  263. }
  264. //Convert the struct to json string
  265. jsonString, _ := json.Marshal(desktopFiles)
  266. utils.SendJSONResponse(w, string(jsonString))
  267. }
  268. // functions to handle desktop icon locations. Location is directly written into the center db.
  269. func getDesktopLocatioFromPath(filename string, username string) (int, int, error) {
  270. //As path include username, there is no different if there are username in the key
  271. locationdata := ""
  272. err := sysdb.Read("desktop", username+"/filelocation/"+filename, &locationdata)
  273. if err != nil {
  274. //The file location is not set. Return error
  275. return -1, -1, errors.New("This file do not have a location registry")
  276. }
  277. type iconLocation struct {
  278. X int
  279. Y int
  280. }
  281. thisFileLocation := iconLocation{
  282. X: -1,
  283. Y: -1,
  284. }
  285. //Start parsing the from the json data
  286. json.Unmarshal([]byte(locationdata), &thisFileLocation)
  287. return thisFileLocation.X, thisFileLocation.Y, nil
  288. }
  289. // Set the icon location of a given filepath
  290. func setDesktopLocationFromPath(filename string, username string, x int, y int) error {
  291. //You cannot directly set path of others people's deskop. Hence, fullpath needed to be parsed from auth username
  292. userinfo, _ := userHandler.GetUserInfoFromUsername(username)
  293. fsh, subpath, _ := GetFSHandlerSubpathFromVpath("user:/Desktop/")
  294. fshAbs := fsh.FileSystemAbstraction
  295. desktoppath, _ := fshAbs.VirtualPathToRealPath(subpath, userinfo.Username)
  296. path := filepath.Join(desktoppath, filename)
  297. type iconLocation struct {
  298. X int
  299. Y int
  300. }
  301. newLocation := new(iconLocation)
  302. newLocation.X = x
  303. newLocation.Y = y
  304. //Check if the file exits
  305. if !fshAbs.FileExists(path) {
  306. return errors.New("Given filename not exists.")
  307. }
  308. //Parse the location to json
  309. jsonstring, err := json.Marshal(newLocation)
  310. if err != nil {
  311. systemWideLogger.PrintAndLog("Desktop", "Unable to parse new file location on desktop for file: "+path, err)
  312. return err
  313. }
  314. //systemWideLogger.PrintAndLog(key,string(jsonstring),nil)
  315. //Write result to database
  316. sysdb.Write("desktop", username+"/filelocation/"+filename, string(jsonstring))
  317. return nil
  318. }
  319. func delDesktopLocationFromPath(filename string, username string) {
  320. //Delete a file icon location from db
  321. sysdb.Delete("desktop", username+"/filelocation/"+filename)
  322. }
  323. // Return the user information to the client
  324. func desktop_handleUserInfo(w http.ResponseWriter, r *http.Request) {
  325. userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
  326. if err != nil {
  327. utils.SendErrorResponse(w, err.Error())
  328. return
  329. }
  330. nic, _ := utils.PostPara(r, "noicon")
  331. noicon := (nic == "true")
  332. type PublicUserInfo struct {
  333. Username string
  334. UserIcon string
  335. UserGroups []string
  336. IsAdmin bool
  337. StorageQuotaTotal int64
  338. StorageQuotaLeft int64
  339. }
  340. //Check if the user is requesting another user's public info
  341. targetUser, err := utils.GetPara(r, "target")
  342. if err == nil {
  343. //User asking for another user's desktop icon
  344. userIcon := ""
  345. searchingUser, err := userHandler.GetUserInfoFromUsername(targetUser)
  346. if err != nil {
  347. utils.SendErrorResponse(w, "User not found")
  348. return
  349. }
  350. //Load the profile image
  351. userIcon = searchingUser.GetUserIcon()
  352. js, _ := json.Marshal(PublicUserInfo{
  353. Username: searchingUser.Username,
  354. UserIcon: userIcon,
  355. IsAdmin: searchingUser.IsAdmin(),
  356. })
  357. utils.SendJSONResponse(w, string(js))
  358. return
  359. }
  360. //Calculate the storage quota left
  361. remainingQuota := userinfo.StorageQuota.TotalStorageQuota - userinfo.StorageQuota.UsedStorageQuota
  362. if userinfo.StorageQuota.TotalStorageQuota == -1 {
  363. remainingQuota = -1
  364. }
  365. //Get the list of user permission group names
  366. pgs := []string{}
  367. for _, pg := range userinfo.GetUserPermissionGroup() {
  368. pgs = append(pgs, pg.Name)
  369. }
  370. rs := PublicUserInfo{
  371. Username: userinfo.Username,
  372. UserIcon: userinfo.GetUserIcon(),
  373. IsAdmin: userinfo.IsAdmin(),
  374. UserGroups: pgs,
  375. StorageQuotaTotal: userinfo.StorageQuota.GetUserStorageQuota(),
  376. StorageQuotaLeft: remainingQuota,
  377. }
  378. if noicon {
  379. rs.UserIcon = ""
  380. }
  381. jsonString, _ := json.Marshal(rs)
  382. utils.SendJSONResponse(w, string(jsonString))
  383. }
  384. // Icon handling function for web endpoint
  385. func desktop_fileLocation_handler(w http.ResponseWriter, r *http.Request) {
  386. get, _ := utils.PostPara(r, "get") //Check if there are get request for a given filepath
  387. set, _ := utils.PostPara(r, "set") //Check if there are any set request for a given filepath
  388. del, _ := utils.PostPara(r, "del") //Delete the given filename coordinate
  389. if set != "" {
  390. //Set location with given paramter
  391. x := 0
  392. y := 0
  393. sx, _ := utils.PostPara(r, "x")
  394. sy, _ := utils.PostPara(r, "y")
  395. path := set
  396. x, err := strconv.Atoi(sx)
  397. if err != nil {
  398. x = 0
  399. }
  400. y, err = strconv.Atoi(sy)
  401. if err != nil {
  402. y = 0
  403. }
  404. //Set location of icon from path
  405. username, _ := authAgent.GetUserName(w, r)
  406. err = setDesktopLocationFromPath(path, username, x, y)
  407. if err != nil {
  408. utils.SendErrorResponse(w, err.Error())
  409. return
  410. }
  411. utils.SendJSONResponse(w, string("\"OK\""))
  412. } else if get != "" {
  413. username, _ := authAgent.GetUserName(w, r)
  414. x, y, _ := getDesktopLocatioFromPath(get, username)
  415. result := []int{x, y}
  416. json_string, _ := json.Marshal(result)
  417. utils.SendJSONResponse(w, string(json_string))
  418. } else if del != "" {
  419. username, _ := authAgent.GetUserName(w, r)
  420. delDesktopLocationFromPath(del, username)
  421. } else {
  422. //No argument has been set
  423. utils.SendJSONResponse(w, "Paramter missing.")
  424. }
  425. }
  426. //////////////////////////////// END OF DESKTOP FILE ICON HANDLER ///////////////////////////////////////////////////
  427. func desktop_theme_handler(w http.ResponseWriter, r *http.Request) {
  428. userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
  429. if err != nil {
  430. utils.SendErrorResponse(w, "User not logged in")
  431. return
  432. }
  433. username := userinfo.Username
  434. //Check if the set GET paramter is set.
  435. targetTheme, _ := utils.GetPara(r, "set")
  436. getUserTheme, _ := utils.GetPara(r, "get")
  437. loadUserTheme, _ := utils.GetPara(r, "load")
  438. if targetTheme == "" && getUserTheme == "" && loadUserTheme == "" {
  439. //List all the currnet themes in the list
  440. themes, err := filepath.Glob("web/img/desktop/bg/*")
  441. if err != nil {
  442. systemWideLogger.PrintAndLog("Desktop", "Unable to search bg from destkop image root. Are you sure the web data folder exists?", err)
  443. return
  444. }
  445. //Prase the results to json array
  446. //Tips: You must use captial letter for varable in struct that is accessable as public :)
  447. type desktopTheme struct {
  448. Theme string
  449. Bglist []string
  450. }
  451. var desktopThemeList []desktopTheme
  452. acceptBGFormats := []string{
  453. ".jpg",
  454. ".png",
  455. ".gif",
  456. }
  457. for _, file := range themes {
  458. if fs.IsDir(file) {
  459. thisTheme := new(desktopTheme)
  460. thisTheme.Theme = filepath.Base(file)
  461. bglist, _ := filepath.Glob(file + "/*")
  462. var thisbglist []string
  463. for _, bg := range bglist {
  464. ext := filepath.Ext(bg)
  465. //if (sliceutil.Contains(acceptBGFormats, ext) ){
  466. if utils.StringInArray(acceptBGFormats, ext) {
  467. //This file extension is supported
  468. thisbglist = append(thisbglist, filepath.Base(bg))
  469. }
  470. }
  471. thisTheme.Bglist = thisbglist
  472. desktopThemeList = append(desktopThemeList, *thisTheme)
  473. }
  474. }
  475. //Return the results as JSON string
  476. jsonString, err := json.Marshal(desktopThemeList)
  477. if err != nil {
  478. systemWideLogger.PrintAndLog("Desktop", "Unable to render desktop wallpaper list", err)
  479. utils.SendJSONResponse(w, string("[]"))
  480. return
  481. }
  482. utils.SendJSONResponse(w, string(jsonString))
  483. return
  484. } else if getUserTheme == "true" {
  485. //Get the user's theme from database
  486. result := ""
  487. sysdb.Read("desktop", username+"/theme", &result)
  488. if result == "" {
  489. //This user has not set a theme yet. Use default
  490. utils.SendJSONResponse(w, string("\"default\""))
  491. return
  492. } else {
  493. //This user already set a theme. Use its set theme
  494. utils.SendJSONResponse(w, string("\""+result+"\""))
  495. return
  496. }
  497. } else if loadUserTheme != "" {
  498. //Load user theme base on folder path
  499. targetFsh, err := userinfo.GetFileSystemHandlerFromVirtualPath(loadUserTheme)
  500. if err != nil {
  501. utils.SendErrorResponse(w, "Unable to resolve user root path")
  502. return
  503. }
  504. fshAbs := targetFsh.FileSystemAbstraction
  505. rpath, err := fshAbs.VirtualPathToRealPath(loadUserTheme, userinfo.Username)
  506. if err != nil {
  507. utils.SendErrorResponse(w, "Custom folder load failed")
  508. return
  509. }
  510. //Check if the folder exists
  511. if !fshAbs.FileExists(rpath) {
  512. utils.SendErrorResponse(w, "Custom folder load failed")
  513. return
  514. }
  515. if !userinfo.CanRead(loadUserTheme) {
  516. //No read permission
  517. utils.SendErrorResponse(w, "Permission denied")
  518. return
  519. }
  520. //Scan for jpg, gif or png
  521. imageList := []string{}
  522. /*
  523. scanPath := filepath.ToSlash(filepath.Clean(rpath)) + "/"
  524. pngFiles, _ := filepath.Glob(scanPath + "*.png")
  525. jpgFiles, _ := filepath.Glob(scanPath + "*.jpg")
  526. gifFiles, _ := filepath.Glob(scanPath + "*.gif")
  527. //Merge all 3 slice into one image list
  528. imageList = append(imageList, pngFiles...)
  529. imageList = append(imageList, jpgFiles...)
  530. imageList = append(imageList, gifFiles...)
  531. */
  532. files, err := fshAbs.ReadDir(rpath)
  533. if err != nil {
  534. utils.SendErrorResponse(w, err.Error())
  535. return
  536. }
  537. for _, file := range files {
  538. ext := filepath.Ext(file.Name())
  539. if utils.StringInArray([]string{".png", ".jpg", ".gif"}, ext) {
  540. imageList = append(imageList, arozfs.ToSlash(filepath.Join(rpath, file.Name())))
  541. }
  542. }
  543. //Convert the image list back to vpaths
  544. virtualImageList := []string{}
  545. for _, image := range imageList {
  546. vpath, err := fshAbs.RealPathToVirtualPath(image, userinfo.Username)
  547. if err != nil {
  548. continue
  549. }
  550. virtualImageList = append(virtualImageList, vpath)
  551. }
  552. js, _ := json.Marshal(virtualImageList)
  553. utils.SendJSONResponse(w, string(js))
  554. } else if targetTheme != "" {
  555. //Set the current user theme
  556. sysdb.Write("desktop", username+"/theme", targetTheme)
  557. utils.SendJSONResponse(w, "\"OK\"")
  558. return
  559. }
  560. }
  561. func desktop_preference_handler(w http.ResponseWriter, r *http.Request) {
  562. preferenceType, _ := utils.PostPara(r, "preference")
  563. value, _ := utils.PostPara(r, "value")
  564. remove, _ := utils.PostPara(r, "remove")
  565. username, err := authAgent.GetUserName(w, r)
  566. if err != nil {
  567. //user not logged in. Redirect to login page.
  568. utils.SendErrorResponse(w, "User not logged in")
  569. return
  570. }
  571. if preferenceType == "" && value == "" {
  572. //Invalid options. Return error reply.
  573. utils.SendErrorResponse(w, "Error. Undefined paramter.")
  574. return
  575. } else if preferenceType != "" && value == "" && remove == "" {
  576. //Getting config from the key.
  577. result := ""
  578. sysdb.Read("desktop", username+"/preference/"+preferenceType, &result)
  579. jsonString, _ := json.Marshal(result)
  580. utils.SendJSONResponse(w, string(jsonString))
  581. return
  582. } else if preferenceType != "" && value == "" && remove == "true" {
  583. //Remove mode
  584. sysdb.Delete("desktop", username+"/preference/"+preferenceType)
  585. utils.SendOK(w)
  586. return
  587. } else if preferenceType != "" && value != "" {
  588. //Setting config from the key
  589. sysdb.Write("desktop", username+"/preference/"+preferenceType, value)
  590. utils.SendOK(w)
  591. return
  592. } else {
  593. utils.SendErrorResponse(w, "Error. Undefined paramter.")
  594. return
  595. }
  596. }
  597. func desktop_shortcutHandler(w http.ResponseWriter, r *http.Request) {
  598. userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
  599. if err != nil {
  600. //user not logged in. Redirect to login page.
  601. utils.SendErrorResponse(w, "User not logged in")
  602. return
  603. }
  604. shortcutType, err := utils.PostPara(r, "stype")
  605. if err != nil {
  606. utils.SendErrorResponse(w, err.Error())
  607. return
  608. }
  609. shortcutText, err := utils.PostPara(r, "stext")
  610. if err != nil {
  611. utils.SendErrorResponse(w, err.Error())
  612. return
  613. }
  614. shortcutPath, err := utils.PostPara(r, "spath")
  615. if err != nil {
  616. utils.SendErrorResponse(w, err.Error())
  617. return
  618. }
  619. shortcutIcon, err := utils.PostPara(r, "sicon")
  620. if err != nil {
  621. utils.SendErrorResponse(w, err.Error())
  622. return
  623. }
  624. shortcutCreationDest, err := utils.PostPara(r, "sdest")
  625. if err != nil {
  626. //Default create on desktop
  627. shortcutCreationDest = "user:/Desktop/"
  628. }
  629. if !userinfo.CanWrite(shortcutCreationDest) {
  630. utils.SendErrorResponse(w, "Permission denied")
  631. return
  632. }
  633. //Resolve vpath to fsh and subpath
  634. fsh, subpath, err := GetFSHandlerSubpathFromVpath(shortcutCreationDest)
  635. if err != nil {
  636. utils.SendErrorResponse(w, err.Error())
  637. return
  638. }
  639. fshAbs := fsh.FileSystemAbstraction
  640. shorcutRealDest, err := fshAbs.VirtualPathToRealPath(subpath, userinfo.Username)
  641. if err != nil {
  642. utils.SendErrorResponse(w, err.Error())
  643. return
  644. }
  645. //Filter illegal characters in the shortcut filename
  646. shortcutText = arozfs.FilterIllegalCharInFilename(shortcutText, " ")
  647. //If dest not exists, create it
  648. if !fshAbs.FileExists(shorcutRealDest) {
  649. fshAbs.MkdirAll(shorcutRealDest, 0755)
  650. }
  651. //Generate a filename for the shortcut
  652. shortcutFilename := shorcutRealDest + "/" + shortcutText + ".shortcut"
  653. counter := 1
  654. for fshAbs.FileExists(shortcutFilename) {
  655. shortcutFilename = shorcutRealDest + "/" + shortcutText + "(" + strconv.Itoa(counter) + ")" + ".shortcut"
  656. counter++
  657. }
  658. //Write the shortcut to file
  659. shortcutContent := shortcut.GenerateShortcutBytes(shortcutPath, shortcutType, shortcutText, shortcutIcon)
  660. err = fshAbs.WriteFile(shortcutFilename, shortcutContent, 0775)
  661. if err != nil {
  662. utils.SendErrorResponse(w, err.Error())
  663. return
  664. }
  665. utils.SendOK(w)
  666. }