MDL-13766, implemented user quota
authorDongsheng Cai <unoter@gmail.com>
Tue, 11 May 2010 06:49:51 +0000 (06:49 +0000)
committerDongsheng Cai <unoter@gmail.com>
Tue, 11 May 2010 06:49:51 +0000 (06:49 +0000)
admin/settings/security.php
lang/en/admin.php
lang/en/error.php
lib/filelib.php
repository/lib.php
repository/repository_ajax.php
repository/upload/repository.class.php
version.php

index b83198b..e067ecd 100644 (file)
@@ -21,11 +21,17 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
         get_string('profileroles','admin'),
         get_string('configprofileroles', 'admin'),
         array('student', 'teacher', 'editingteacher')));
-    
+
     $max_upload_choices = get_max_upload_sizes();
     // maxbytes set to 0 will allow the maxium server lmit for uploads
     $max_upload_choices[0] = get_string('serverlimit', 'admin');
     $temp->add(new admin_setting_configselect('maxbytes', get_string('maxbytes', 'admin'), get_string('configmaxbytes', 'admin'), 0, $max_upload_choices));
+    // 100MB
+    $defaultuserquota = 104857600;
+    $params = new stdclass;
+    $params->bytes = $defaultuserquota;
+    $params->displaysize = display_size($defaultuserquota);
+    $temp->add(new admin_setting_configtext('userquota', get_string('userquota', 'admin'), get_string('configuserquota', 'admin', $params), $defaultuserquota));
 
     $temp->add(new admin_setting_configcheckbox('allowobjectembed', get_string('allowobjectembed', 'admin'), get_string('configallowobjectembed', 'admin'), 0));
     $temp->add(new admin_setting_configcheckbox('enabletrusttext', get_string('enabletrusttext', 'admin'), get_string('configenabletrusttext', 'admin'), 0));
@@ -77,7 +83,7 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
     // "modulesecurity" settingpage
     $temp = new admin_settingpage('modulesecurity', get_string('modulesecurity', 'admin'));
     $temp->add(new admin_setting_configselect('restrictmodulesfor', get_string('restrictmodulesfor', 'admin'), get_string('configrestrictmodulesfor', 'admin'), 'none', array('none' => get_string('nocourses'),
-                                                                                                                                                                              'all' => get_string('fulllistofcourses'), 
+                                                                                                                                                                              'all' => get_string('fulllistofcourses'),
                                                                                                                                                                               'requested' => get_string('requestedcourses'))));
     $temp->add(new admin_setting_configcheckbox('restrictbydefault', get_string('restrictbydefault', 'admin'), get_string('configrestrictbydefault', 'admin'), 0));
     if (!$options = $DB->get_records('modules')) {
index dabbaae..d4f04d7 100755 (executable)
@@ -303,6 +303,7 @@ $string['configrestrictbydefault'] = 'Should new courses that are created that f
 $string['configrestrictmodulesfor'] = 'Which courses should have <b>the setting</b> for disabling some activity modules?  Note that this setting only applies to teachers, administrators will still be able to add any activity to a course.';
 $string['configrunclamavonupload'] = 'When enabled, clam AV will be used to scan all uploaded files.';
 $string['configrunclamonupload'] = 'Run clam AV on file upload? You will need a correct path in pathtoclam for this to work.  (Clam AV is a free virus scanner that you can get from http://www.clamav.net/)';
+$string['configuserquota'] = 'The maxbytes if files that user can use in user area, the value is in bytes. <b>{$a->bytes} bytes == {$a->displaysize}</b>';
 $string['configsectioninterface'] = 'Interface';
 $string['configsectionmail'] = 'Mail';
 $string['configsectionmaintenance'] = 'Maintenance';
@@ -983,6 +984,7 @@ $string['usersrenamed'] = 'Users renamed';
 $string['usersskipped'] = 'Users skipped';
 $string['usersupdated'] = 'Users updated';
 $string['usersweakpassword'] = 'Users having a weak password';
+$string['userquota'] = 'User quota';
 $string['usetags'] = 'Enable tags functionality';
 $string['uubulk'] = 'Select for bulk operations';
 $string['uubulkall'] = 'All users';
index 08afe1b..c894dd2 100755 (executable)
@@ -494,6 +494,7 @@ $string['usernotrenamedoff'] = 'User not renamed - renaming not allowed';
 $string['usernotupdatedadmin'] = 'Cannot update admin accounts';
 $string['usernotupdatederror'] = 'User not updated - error';
 $string['usernotupdatednotexists'] = 'User not updated - does not exist';
+$string['userquotalimit'] = 'You have reached your file quota limit.';
 $string['userselectortoomany'] = 'user_selector got more than one selected user, even though multiselect is false.';
 $string['wrongcall'] = 'This script is called wrongly';
 $string['wrongcontextid'] = 'Context ID was incorrect (cannot find it)';
index e4ee837..be696ff 100644 (file)
@@ -499,6 +499,35 @@ function file_get_user_area_info($draftitemid, $filearea = 'user_draft') {
     return $results;
 }
 
+/**
+ * Get used space of files
+ * @return int totalbytes
+ */
+function file_get_user_used_space() {
+    global $DB, $CFG, $USER;
+
+    $usercontext = get_context_instance(CONTEXT_USER, $USER->id);
+    $fs = get_file_storage();
+
+    // only count files in user context
+    $conditions = array('contextid'=>$usercontext->id);
+
+    $totalbytes = 0;
+    $files = array();
+    $file_records = $DB->get_records('files', $conditions);
+    foreach ($file_records as $file_record) {
+        if ($file_record->filename === '.') {
+            continue;
+        }
+        // doesn't count same files
+        if (!isset($files[$file_record->contenthash])) {
+            $totalbytes += $file_record->filesize;
+        } else {
+            $files[$file_record->contenthash] = true;
+        }
+    }
+    return (int)$totalbytes;
+}
 
 /**
  * Convert any string to a valid filepath
@@ -845,7 +874,7 @@ function format_postdata_for_curlcall($postdata) {
                 $currentdata = urlencode($k);
                 format_array_postdata_for_curlcall($v, $currentdata, $data);
             }  else {
-                $data[] = urlencode($k).'='.urlencode($v);            
+                $data[] = urlencode($k).'='.urlencode($v);
             }
         }
         $convertedpostdata = implode('&', $data);
@@ -927,7 +956,7 @@ function download_file_content($url, $headers=null, $postdata=null, $fullrespons
         curl_setopt($ch, CURLOPT_POST, true);
         curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);
     }
-    
+
     curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
     curl_setopt($ch, CURLOPT_HEADER, true);
     curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connecttimeout);
index 32e209f..936b1e6 100644 (file)
@@ -528,7 +528,7 @@ abstract class repository {
         }
         if ($records = $DB->get_records('repository',$params,'sortorder')) {
             foreach($records as $type) {
-                if (file_exists($CFG->dirroot . '/repository/'. $type->type .'/repository.class.php')) { 
+                if (file_exists($CFG->dirroot . '/repository/'. $type->type .'/repository.class.php')) {
                     $types[] = new repository_type($type->type, (array)get_config($type->type), $type->visible, $type->sortorder);
                 }
             }
@@ -1805,7 +1805,7 @@ function initialise_filepicker($args) {
     $repositories = repository::get_instances(array(
         'context'=>array($user_context, get_system_context()),
         'currentcontext'=> $context,
-        'accepted_types'=>$args->accepted_types, 
+        'accepted_types'=>$args->accepted_types,
         'return_types'=>$args->return_types
     ));
 
index 3f43214..dbddc49 100755 (executable)
@@ -59,8 +59,10 @@ header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
 $err = new stdclass;
 $err->client_id = $client_id;
 
-if ($maxbytes == 0) {
-    $maxbytes = get_max_upload_file_size();
+$moodle_maxbytes = get_max_upload_file_size();
+// to prevent maxbytes greater than moodle maxbytes setting
+if ($maxbytes == 0 || $maxbytes>=$moodle_maxbytes) {
+    $maxbytes = $moodle_maxbytes;
 }
 
 /// Check permissions
@@ -221,9 +223,10 @@ switch ($action) {
         break;
     case 'download':
         try {
-            // we have two special repoisitory type need to deal with
+            // We have two special repoisitory type need to deal with
+            // local and recent plugins don't added new files to moodle, just add new records to database
+            // so we don't check user quota and maxbytes here
             if ($repo->options['type'] == 'local' || $repo->options['type'] == 'recent' ) {
-                // saveas_filearea
                 try {
                     $fileinfo = $repo->copy_to_area($source, $saveas_filearea, $itemid, $saveas_path, $saveas_filename);
                 } catch (Exception $e) {
@@ -250,11 +253,13 @@ switch ($action) {
                 // allow external links in url element all the time
                 $allowexternallink = ($allowexternallink || ($env == 'url'));
 
+                // Use link of the files
                 if ($allowexternallink and $linkexternal === 'yes' and ($repo->supported_returntypes() || FILE_EXTERNAL)) {
                     // use external link
                     try {
                         $link = $repo->get_link($source);
                     } catch (repository_exception $e){
+                        throw $e;
                     }
                     $info = array();
                     $info['filename'] = $saveas_filename;
@@ -263,16 +268,24 @@ switch ($action) {
                     echo json_encode($info);
                     die;
                 } else {
-                    // get the file location
+                    // Download file to moodle
                     $file = $repo->get_file($source, $saveas_filename);
                     if ($file['path'] === false) {
                         $err->e = get_string('cannotdownload', 'repository');
                         die(json_encode($err));
                     }
+
+                    // check if exceed maxbytes
                     if (($maxbytes!==-1) && (filesize($file['path']) > $maxbytes)) {
                         throw new file_exception('maxbytes');
                     }
 
+                    // check if exceed user quota
+                    $userquota = file_get_user_used_space();
+                    if (filesize($file['path'])+$userquota>=(int)$CFG->userquota) {
+                        throw new file_exception('userquotalimit');
+                    }
+
                     $record = new stdclass;
                     $record->filepath = $saveas_path;
                     $record->filename = $saveas_filename;
@@ -299,9 +312,6 @@ switch ($action) {
                     die;
                 }
             }
-        } catch (repository_exception $e){
-            $err->e = $e->getMessage();
-            die(json_encode($err));
         } catch (Exception $e) {
             $err->e = $e->getMessage();
             die(json_encode($err));
index c92e086..8e0f362 100755 (executable)
@@ -116,7 +116,7 @@ class repository_upload extends repository {
      * @return mixed stored_file object or false if error; may throw exception if duplicate found
      */
     public function upload_to_filepool($elname, $record, $override = true) {
-        global $USER;
+        global $USER, $CFG;
         $context = get_context_instance(CONTEXT_USER, $USER->id);
         $fs = get_file_storage();
         $browser = get_file_browser();
@@ -138,6 +138,11 @@ class repository_upload extends repository {
             $record->filename = $_FILES[$elname]['name'];
         }
 
+        $userquota = file_get_user_used_space();
+        if (filesize($_FILES[$elname]['tmp_name'])+$userquota>=(int)$CFG->userquota) {
+            throw new file_exception('userquotalimit');
+        }
+
         if (empty($record->itemid)) {
             $record->itemid = 0;
         }
index 8dbf2f5..f9931dd 100644 (file)
@@ -6,7 +6,7 @@
 // This is compared against the values stored in the database to determine
 // whether upgrades should be performed (see lib/db/*.php)
 
-    $version = 2010050411;  // YYYYMMDD   = date of the last version bump
+    $version = 2010050412;  // YYYYMMDD   = date of the last version bump
                             //         XX = daily increments
 
     $release = '2.0 Preview 1 (Build: 20100511)';  // Human-friendly version name