aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mediagoblin/config_spec.ini3
-rw-r--r--mediagoblin/db/migrations.py24
-rw-r--r--mediagoblin/db/models.py3
-rw-r--r--mediagoblin/storage/__init__.py7
-rw-r--r--mediagoblin/storage/cloudfiles.py6
-rw-r--r--mediagoblin/storage/filestorage.py3
-rw-r--r--mediagoblin/submit/views.py34
-rw-r--r--mediagoblin/user_pages/views.py4
8 files changed, 82 insertions, 2 deletions
diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini
index 8f03509d..596e4388 100644
--- a/mediagoblin/config_spec.ini
+++ b/mediagoblin/config_spec.ini
@@ -75,6 +75,9 @@ theme = string()
plugin_web_path = string(default="/plugin_static/")
plugin_linked_assets_dir = string(default="%(here)s/user_dev/plugin_static/")
+# User upload limit (in Mbs)
+upload_limit = integer(default=500)
+
[jinja2]
# Jinja2 supports more directives than the minimum required by mediagoblin.
# This setting allows users creating custom templates to specify a list of
diff --git a/mediagoblin/db/migrations.py b/mediagoblin/db/migrations.py
index 374ab4c8..b3dca72c 100644
--- a/mediagoblin/db/migrations.py
+++ b/mediagoblin/db/migrations.py
@@ -425,7 +425,7 @@ class RequestToken_v0(declarative_base()):
callback = Column(Unicode, nullable=False, default=u"oob")
created = Column(DateTime, nullable=False, default=datetime.datetime.now)
updated = Column(DateTime, nullable=False, default=datetime.datetime.now)
-
+
class AccessToken_v0(declarative_base()):
"""
Model for representing the access tokens
@@ -438,7 +438,7 @@ class AccessToken_v0(declarative_base()):
request_token = Column(Unicode, ForeignKey(RequestToken_v0.token))
created = Column(DateTime, nullable=False, default=datetime.datetime.now)
updated = Column(DateTime, nullable=False, default=datetime.datetime.now)
-
+
class NonceTimestamp_v0(declarative_base()):
"""
@@ -460,3 +460,23 @@ def create_oauth1_tables(db):
NonceTimestamp_v0.__table__.create(db.bind)
db.commit()
+
+
+@RegisterMigration(15, MIGRATIONS)
+def upload_limits(db):
+ """Add user upload limit columns"""
+ metadata = MetaData(bind=db.bind)
+
+ user_table = inspect_table(metadata, 'core__users')
+ media_entry_table = inspect_table(metadata, 'core__media_entries')
+
+ col = Column('uploaded', Integer, default=0)
+ col.create(user_table)
+
+ col = Column('upload_limit', Integer)
+ col.create(user_table)
+
+ col = Column('file_size', Integer, default=0)
+ col.create(media_entry_table)
+
+ db.commit()
diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py
index 9cb39ff4..697ee326 100644
--- a/mediagoblin/db/models.py
+++ b/mediagoblin/db/models.py
@@ -73,6 +73,8 @@ class User(Base, UserMixin):
is_admin = Column(Boolean, default=False, nullable=False)
url = Column(Unicode)
bio = Column(UnicodeText) # ??
+ uploaded = Column(Integer, default=0)
+ upload_limit = Column(Integer)
## TODO
# plugin data would be in a separate model
@@ -189,6 +191,7 @@ class MediaEntry(Base, MediaEntryMixin):
# or use sqlalchemy.types.Enum?
license = Column(Unicode)
collected = Column(Integer, default=0)
+ file_size = Column(Integer, default=0)
fail_error = Column(Unicode)
fail_metadata = Column(JSONEncoded)
diff --git a/mediagoblin/storage/__init__.py b/mediagoblin/storage/__init__.py
index bbe134a7..51b46c07 100644
--- a/mediagoblin/storage/__init__.py
+++ b/mediagoblin/storage/__init__.py
@@ -191,6 +191,13 @@ class StorageInterface(object):
# Copy to storage system in 4M chunks
shutil.copyfileobj(source_file, dest_file, length=4*1048576)
+ def get_file_size(self, filepath):
+ """
+ Return the size of the file in bytes.
+ """
+ # Subclasses should override this method.
+ self.__raise_not_implemented()
+
###########
# Utilities
diff --git a/mediagoblin/storage/cloudfiles.py b/mediagoblin/storage/cloudfiles.py
index 250f06d4..47c81ad6 100644
--- a/mediagoblin/storage/cloudfiles.py
+++ b/mediagoblin/storage/cloudfiles.py
@@ -168,6 +168,12 @@ class CloudFilesStorage(StorageInterface):
# Copy to storage system in 4096 byte chunks
dest_file.send(source_file)
+ def get_file_size(self, filepath):
+ """Returns the file size in bytes"""
+ obj = self.container.get_object(
+ self._resolve_filepath(filepath))
+ return obj.total_bytes
+
class CloudFilesStorageObjectWrapper():
"""
Wrapper for python-cloudfiles's cloudfiles.storage_object.Object
diff --git a/mediagoblin/storage/filestorage.py b/mediagoblin/storage/filestorage.py
index 3d6e0753..29b8383b 100644
--- a/mediagoblin/storage/filestorage.py
+++ b/mediagoblin/storage/filestorage.py
@@ -111,3 +111,6 @@ class BasicFileStorage(StorageInterface):
os.makedirs(directory)
# This uses chunked copying of 16kb buffers (Py2.7):
shutil.copy(filename, self.get_local_path(filepath))
+
+ def get_file_size(self, filepath):
+ return os.stat(self._resolve_filepath(filepath)).st_size
diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py
index 6bb95ecb..d5f05cb7 100644
--- a/mediagoblin/submit/views.py
+++ b/mediagoblin/submit/views.py
@@ -43,6 +43,20 @@ def submit_start(request):
"""
First view for submitting a file.
"""
+ user = request.user
+ if user.upload_limit:
+ upload_limit = user.upload_limit
+ else:
+ upload_limit = mg_globals.app_config['upload_limit']
+
+ if user.uploaded >= upload_limit:
+ messages.add_message(
+ request,
+ messages.WARNING,
+ _('Sorry, you have reached your upload limit.'))
+ return redirect(
+ request, '/u/{0}'.format(user.username))
+
submit_form = submit_forms.SubmitStartForm(request.form,
license=request.user.license_preference)
@@ -86,6 +100,26 @@ def submit_start(request):
with queue_file:
queue_file.write(request.files['file'].stream.read())
+ # Get file size an round to 2 decimal places
+ file_size = request.app.queue_store.get_file_size(
+ entry.queued_media_file) / (1024.0 * 1024)
+ file_size = float('{0:.2f}'.format(file_size))
+
+ # Check if over upload limit
+ if (user.uploaded + file_size) >= upload_limit:
+ messages.add_message(
+ request,
+ messages.WARNING,
+ _('Sorry, uploading this file will put you over your'
+ ' upload limit.'))
+ return redirect(
+ request, '/u/{0}'.format(user.username))
+
+ user.uploaded = user.uploaded + file_size
+ user.save()
+
+ entry.file_size = file_size
+
# Save now so we have this data before kicking off processing
entry.save()
diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py
index 49691a29..3b411fe0 100644
--- a/mediagoblin/user_pages/views.py
+++ b/mediagoblin/user_pages/views.py
@@ -296,6 +296,10 @@ def media_confirm_delete(request, media):
if request.method == 'POST' and form.validate():
if form.confirm.data is True:
username = media.get_uploader.username
+
+ request.user.uploaded = request.user.uploaded - media.file_size
+ request.user.save()
+
# Delete MediaEntry and all related files, comments etc.
media.delete()
messages.add_message(