desktop.go 20 KB

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