123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302 |
- package main
- import (
- "encoding/json"
- "errors"
- "net/http"
- "os"
- "path/filepath"
- "sort"
- "strings"
- "log"
- )
- /*
- Disk Quota Management System
- This module manage the user groups disk quota in the system
- Disk quota can only be set on a user group bases.
- (aka all users in the same group has the identical number of disk quota to the group settings)
- */
- func system_disk_quota_init() {
- //Initiate quota storage table
- err := sysdb.NewTable("diskquota")
- if err != nil {
- panic(err)
- }
- //Register Endpoints
- http.HandleFunc("/system/disk/quota/setQuota", system_disk_quota_setQuota)
- http.HandleFunc("/system/disk/quota/listQuota", system_disk_quota_listQuota)
- http.HandleFunc("/system/disk/quota/quotaInfo", system_disk_quota_handleQuotaInfo)
- http.HandleFunc("/system/disk/quota/quotaDist", system_disk_quota_handleFileDistributionView)
- //Register Setting Interfaces
- //Register interface fow viewing the user storage quota
- registerSetting(settingModule{
- Name: "Storage Quota",
- Desc: "User Remaining Space",
- IconPath: "SystemAO/disk/quota/img/small_icon.png",
- Group: "Disk",
- StartDir: "SystemAO/disk/quota/quota.system",
- })
- //Register interface for admin to setup quota settings
- registerSetting(settingModule{
- Name: "Quota Settings",
- Desc: "Setup Group Storage Limit",
- IconPath: "SystemAO/disk/quota/img/small_icon.png",
- Group: "Disk",
- StartDir: "SystemAO/disk/quota/manage.html",
- RequireAdmin: true,
- })
- }
- //Get a list of quota on user groups and their storage limit
- func system_disk_quota_listQuota(w http.ResponseWriter, r *http.Request) {
- _, err := authAgent.GetUserName(w,r);
- if err != nil {
- sendErrorResponse(w, "User not logged in")
- return
- }
- isAdmin := system_permission_checkUserIsAdmin(w, r)
- if !isAdmin {
- sendErrorResponse(w, "Permission denied")
- return
- }
- groups := system_permission_listGroup()
- results := map[string]int64{}
- for _, group := range groups {
- quota, _ := system_disk_quota_getQuotaFromGroupname(group)
- results[group] = quota
- }
- jsonString, _ := json.Marshal(results)
- sendJSONResponse(w, string(jsonString))
- }
- //Check the storage quota on this usergroup. Return -1 for unlimited quota and 0 if error
- func system_disk_quota_getQuotaFromGroupname(groupname string) (int64, error) {
- //If administrator, always return -1
- if groupname == "administrator" {
- return -1, nil
- }
- //Check if group exists
- if !system_permission_groupExists(groupname) {
- return 0, errors.New("Group not exists")
- }
- //Group exists. Get the group quota from db
- groupQuota := int64(0)
- err := sysdb.Read("diskquota", "quota/"+groupname, &groupQuota)
- if err != nil {
- return 0, err
- }
- return groupQuota, nil
- }
- //Check if the given size can fit into the user remaining quota, return true if the file fit user quota
- func system_disk_quota_validateQuota(username string, filesize int64) bool {
- remaining, _, _, err := system_disk_quota_quotaInfo(username)
- if err != nil{
- log.Println("Upload failed for user: " + username + " " + err.Error())
- return false
- }
- //log.Println(remaining, filesize, err)
- if remaining == -1{
- //Unlimited quota. Always return true
- return true
- }else if (remaining == 0){
- //Read only account. Always return false
- return false
- }else if (remaining >= filesize ){
- //This file fits in the user's remaining space
- return true
- }else{
- return false
- }
- return false
- }
- //Check if the given path apply quota limitation
- func system_disk_quota_checkIfQuotaApply(path string, username string) bool{
- targetStoargeDevice, err := system_storage_getStorageByPath(path, username);
- if (err != nil){
- return false
- }
- if targetStoargeDevice.Hierarchy == "user"{
- //User Hierarchy Storage Device, count as user's private storage
- return true
- }
- //Not user's private storage. Calculate as public one
- return false
- }
- //Set the storage quota of the particular user
- func system_disk_quota_setQuota(w http.ResponseWriter, r *http.Request) {
- authed := authAgent.CheckAuth(r)
- if !authed {
- sendErrorResponse(w, "User not logged in")
- return
- }
- isAdmin := system_permission_checkUserIsAdmin(w, r)
- if !isAdmin {
- sendErrorResponse(w, "Permission denied")
- return
- }
- //OK to proceed
- groupname, err := mv(r, "groupname", true)
- if err != nil {
- sendErrorResponse(w, "Group name not defned")
- return
- }
- quotaSizeString, err := mv(r, "quota", true)
- if err != nil {
- sendErrorResponse(w, "Quota not defined")
- return
- }
- quotaSize, err := StringToInt64(quotaSizeString)
- if err != nil || quotaSize < 0 {
- sendErrorResponse(w, "Invalid quota size given")
- return
- }
- //Qutasize unit is in MB
- quotaSize = quotaSize << 20
- //Check groupname exists
- if !system_permission_groupExists(groupname) {
- sendErrorResponse(w, "Group name not exists. Given "+groupname)
- return
- }
- //Ok to proceed.
- err = sysdb.Write("diskquota", "quota/"+groupname, quotaSize)
- if err != nil {
- sendErrorResponse(w, err.Error())
- return
- }
- sendOK(w)
- }
- //Show the current user's quota information
- func system_disk_quota_handleQuotaInfo(w http.ResponseWriter, r *http.Request) {
- username, err := authAgent.GetUserName(w,r);
- if err != nil {
- sendErrorResponse(w, "User not logged in")
- return
- }
- remainingSpace, usedSpace, totalSpace, err := system_disk_quota_quotaInfo(username)
- type quotaInformation struct {
- Remaining int64
- Used int64
- Total int64
- }
- jsonString, _ := json.Marshal(quotaInformation{
- Remaining: remainingSpace,
- Used: usedSpace,
- Total: totalSpace,
- })
- sendJSONResponse(w, string(jsonString))
- }
- //Get all the users file and see how
- func system_disk_quota_handleFileDistributionView(w http.ResponseWriter, r *http.Request) {
- //Check if the user logged in
- username, err := authAgent.GetUserName(w,r);
- if err != nil {
- sendErrorResponse(w, "User not logged in")
- return
- }
- //Create a file distribution list
- fileDist := map[string]int64{}
- userpaths := system_storage_getUserDirectory(username)
- for _, thispath := range userpaths {
- filepath.Walk(thispath, func(filepath string, info os.FileInfo, err error) error {
- if err != nil {
- return err
- }
- if !info.IsDir() {
- mime, _, err := system_fs_getMime(filepath)
- if err != nil {
- return err
- }
- mediaType := strings.SplitN(mime, "/", 2)[0]
- mediaType = strings.Title(mediaType)
- fileDist[mediaType] = fileDist[mediaType] + info.Size()
- }
- return err
- })
- }
- //Sort the file according to the number of files in the
- type kv struct {
- Mime string
- Size int64
- }
- var ss []kv
- for k, v := range fileDist {
- ss = append(ss, kv{k, v})
- }
- sort.Slice(ss, func(i, j int) bool {
- return ss[i].Size > ss[j].Size
- })
- //Return the distrubution using json string
- jsonString, _ := json.Marshal(ss)
- sendJSONResponse(w, string(jsonString))
- }
- //Get the quota information of the current user. Return the followings
- /*
- Remaining space of the user quota (int64)
- Used space of the user quota (int64)
- Total theoretical space of the user quota (int64)
- Error (error). Standard error message if something goes wrong
- */
- func system_disk_quota_quotaInfo(username string) (int64, int64, int64, error) {
- //Get the user group information
- usergroup := system_permission_getUserPermissionGroup(username)
- groupExists := system_permission_groupExists(usergroup)
- if !groupExists {
- return 0, 0, 0, errors.New("User group not exists")
- }
- //Get the group quota information
- groupQuota := int64(-1)
- sysdb.Read("diskquota", "quota/"+usergroup, &groupQuota)
- //Calculate user limit
- userpaths := system_storage_getUserDirectory(username)
- totalUserUsedSpace := int64(0)
- for _, thispath := range userpaths {
- filepath.Walk(thispath, func(_ string, info os.FileInfo, err error) error {
- if err != nil {
- return err
- }
- if !info.IsDir() {
- totalUserUsedSpace += info.Size()
- }
- return err
- })
- }
- remainingSpace := groupQuota - totalUserUsedSpace
- if groupQuota == -1 {
- remainingSpace = -1
- }
- return remainingSpace, totalUserUsedSpace, groupQuota, nil
- }
|