diff --git a/.gitignore b/.gitignore
index d6170257f..4c24d609b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,12 @@
-.venv/*
+# General
*.pyc
*.swp
*~
+
+# Virtual Environment
+.venv/*
+
+# Development settings and database
settings.py
database.sqlite
!tests/settings.py
@@ -14,6 +19,6 @@ dist/*
.DS_Store
versiontools*
-# Unit test / coverage reports
+# Unit test and coverage reports
.coverage
htmlcov
diff --git a/openslides/global_settings.py b/openslides/global_settings.py
index aec335377..c74bbd4ce 100644
--- a/openslides/global_settings.py
+++ b/openslides/global_settings.py
@@ -1,12 +1,12 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
- openslides.openslides_settings
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ openslides.global_settings
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
OpenSlides default settings.
- :copyright: 2011, 2012 by OpenSlides team, see AUTHORS.
+ :copyright: 2011–2013 by OpenSlides team, see AUTHORS.
:license: GNU GPL, see LICENSE for more details.
"""
@@ -15,6 +15,7 @@ import sys
from openslides.main import fs2unicode
+
SITE_ROOT = os.path.realpath(os.path.dirname(__file__))
AUTHENTICATION_BACKENDS = (
@@ -34,7 +35,6 @@ LANGUAGES = (
('fr', ugettext('French')),
)
-
# If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery.
USE_I18N = True
@@ -47,18 +47,14 @@ LOCALE_PATHS = (
fs2unicode(os.path.join(SITE_ROOT, 'locale')),
)
-# Absolute path to the directory that holds media.
-# Example: "/home/media/media.lawrence.com/"
-MEDIA_ROOT = fs2unicode(os.path.join(SITE_ROOT, './static/'))
-
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash if there is a path component (optional in other cases).
# Examples: "http://media.lawrence.com", "http://example.com/media/"
-MEDIA_URL = ''
+MEDIA_URL = '/media/'
# Absolute path to the directory that holds static media from ``collectstatic``
# Example: "/home/media/static.lawrence.com/"
-STATIC_ROOT = fs2unicode(os.path.join(SITE_ROOT, '../site-static'))
+STATIC_ROOT = fs2unicode(os.path.join(SITE_ROOT, '../collected-site-static'))
# URL that handles the media served from STATIC_ROOT. Make sure to use a
# trailing slash if there is a path component (optional in other cases).
@@ -119,6 +115,7 @@ INSTALLED_APPS = (
'openslides.motion',
'openslides.assignment',
'openslides.participant',
+ 'openslides.mediafile',
'openslides.config',
)
diff --git a/openslides/main.py b/openslides/main.py
index b7107317d..4477b6a51 100644
--- a/openslides/main.py
+++ b/openslides/main.py
@@ -6,7 +6,7 @@
Main script to start and set up OpenSlides.
- :copyright: 2011, 2012 by OpenSlides team, see AUTHORS.
+ :copyright: 2011–2013 by OpenSlides team, see AUTHORS.
:license: GNU GPL, see LICENSE for more details.
"""
@@ -64,6 +64,11 @@ INSTALLED_PLUGINS = (
)
INSTALLED_APPS += INSTALLED_PLUGINS
+
+# Absolute path to the directory that holds media.
+# Example: "/home/media/media.lawrence.com/"
+MEDIA_ROOT = %(media_root_path)s
+
"""
KEY_LENGTH = 30
@@ -195,14 +200,17 @@ def create_settings(settings_path, database_path=None):
if database_path is _portable_db_path:
database_path = get_portable_db_path()
dbpath_value = 'openslides.main.get_portable_db_path()'
+ media_root_path_value = 'openslides.main.get_portable_media_root_path()'
else:
if database_path is None:
database_path = get_user_data_path('openslides', 'database.sqlite')
dbpath_value = repr(fs2unicode(database_path))
+ media_root_path_value = repr(fs2unicode(get_user_data_path('openslides', 'media', '')))
settings_content = CONFIG_TEMPLATE % dict(
default_key=base64.b64encode(os.urandom(KEY_LENGTH)),
- dbpath=dbpath_value)
+ dbpath=dbpath_value,
+ media_root_path=media_root_path_value)
if not os.path.exists(settings_module):
os.makedirs(settings_module)
@@ -370,6 +378,10 @@ def get_portable_db_path():
return get_portable_path('openslides', 'database.sqlite')
+def get_portable_media_root_path():
+ return get_portable_path('openslides', 'media', '')
+
+
def win32_get_app_data_path(*args):
shell32 = ctypes.WinDLL("shell32.dll")
SHGetFolderPath = shell32.SHGetFolderPathW
diff --git a/openslides/mediafile/__init__.py b/openslides/mediafile/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/openslides/mediafile/forms.py b/openslides/mediafile/forms.py
new file mode 100644
index 000000000..b9a94d0c0
--- /dev/null
+++ b/openslides/mediafile/forms.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+ openslides.mediafile.forms
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Forms for the mediafile app.
+
+ :copyright: 2011–2013 by OpenSlides team, see AUTHORS.
+ :license: GNU GPL, see LICENSE for more details.
+"""
+
+from django.forms import ModelForm
+
+from openslides.utils.forms import CssClassMixin
+
+from .models import Mediafile
+
+
+class MediafileNormalUserCreateForm(CssClassMixin, ModelForm):
+ """Form to create a media file.
+
+ This form is only used by normal users, not by managers.
+
+ """
+ class Meta:
+ model = Mediafile
+ exclude = ('uploader',)
+
+
+class MediafileUpdateForm(CssClassMixin, ModelForm):
+ """Form to edit mediafile entries.
+
+ This form is only for managers to update the mediafile entry.
+
+ """
+ class Meta:
+ model = Mediafile
+
+ def save(self, *args, **kwargs):
+ """Method to save the form.
+
+ Here the overwrite is to delete old files.
+
+ """
+ if not self.instance.pk is None:
+ old_file = Mediafile.objects.get(pk=self.instance.pk).mediafile
+ if not old_file == self.instance.mediafile:
+ old_file.delete()
+ return super(MediafileUpdateForm, self).save(*args, **kwargs)
diff --git a/openslides/mediafile/models.py b/openslides/mediafile/models.py
new file mode 100644
index 000000000..f870e3100
--- /dev/null
+++ b/openslides/mediafile/models.py
@@ -0,0 +1,85 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+ openslides.mediafile.models
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Models for the mediafile app.
+
+ :copyright: 2011–2013 by OpenSlides team, see AUTHORS.
+ :license: GNU GPL, see LICENSE for more details.
+"""
+
+import mimetypes
+
+from django.db import models
+from django.utils.translation import ugettext_noop
+
+from openslides.utils.person.models import PersonField
+
+
+class Mediafile(models.Model):
+ """The Mediafile class
+
+ Class for uploaded files which can be delivered under a certain url.
+
+ """
+ mediafile = models.FileField(upload_to='file')
+ """A FileField
+
+ See https://docs.djangoproject.com/en/dev/ref/models/fields/#filefield
+ for more information.
+
+ """
+ title = models.CharField(max_length=255, unique=True)
+ """A string representing the title of the file."""
+
+ uploader = PersonField(blank=True)
+ """A person – the uploader of a file."""
+
+ timestamp = models.DateTimeField(auto_now_add=True)
+ """A DateTimeField to save the upload date and time."""
+
+ filetype = models.CharField(max_length=255, editable=False)
+ """A string used to show the type of the file."""
+
+ class Meta:
+ """Meta class for the mediafile model."""
+ ordering = ['title']
+ permissions = (
+ ('can_see', ugettext_noop('Can see the list of files')),
+ ('can_upload', ugettext_noop('Can upload files')),
+ ('can_manage', ugettext_noop('Can manage files')),)
+
+ def __unicode__(self):
+ """Method for representation."""
+ return self.title
+
+ def save(self, *args, **kwargs):
+ """Method to read filetype and then save to the database."""
+ if self.mediafile:
+ self.filetype = mimetypes.guess_type(self.mediafile.path)[0] or ugettext_noop('unknown')
+ else:
+ self.filetype = ugettext_noop('unknown')
+ return super(Mediafile, self).save(*args, **kwargs)
+
+ @models.permalink
+ def get_absolute_url(self, link='update'):
+ """Returns the URL to a mediafile. The link can be 'update' or 'delete'."""
+ if link == 'update' or link == 'edit': # 'edit' ist only used until utils/views.py is fixed
+ return ('mediafile_update', [str(self.id)])
+ if link == 'delete':
+ return ('mediafile_delete', [str(self.id)])
+
+ def get_filesize(self):
+ """Transforms Bytes to Kilobytes or Megabytes. Returns the size as string."""
+ size = self.mediafile.size
+ if size < 1024:
+ return '< 1 kB'
+ if size >= 1024 * 1024:
+ mB = size / 1024 / 1024
+ return '%d MB' % mB
+ else:
+ kB = size / 1024
+ return '%d kB' % kB
+ # TODO: Read http://stackoverflow.com/a/1094933 and think about it.
diff --git a/openslides/mediafile/static/styles/mediafile.css b/openslides/mediafile/static/styles/mediafile.css
new file mode 100644
index 000000000..99f7d28cd
--- /dev/null
+++ b/openslides/mediafile/static/styles/mediafile.css
@@ -0,0 +1,12 @@
+/*
+ * OpenSlides mediafile style
+ *
+ * :copyright: 2011–2013 by OpenSlides team, see AUTHORS.
+ * :license: GNU GPL, see LICENSE for more details.
+ */
+
+/** Navigation icons (mapping to glyphicons-halflings) **/
+
+.icon-mediafile {
+ background-position: -96px -24px;
+}
diff --git a/openslides/mediafile/templates/mediafile/mediafile_form.html b/openslides/mediafile/templates/mediafile/mediafile_form.html
new file mode 100644
index 000000000..f709153d3
--- /dev/null
+++ b/openslides/mediafile/templates/mediafile/mediafile_form.html
@@ -0,0 +1,37 @@
+{% extends 'base.html' %}
+
+{% load i18n %}
+
+{% block title %}
+ {{ block.super }} –
+ {% if mediafile %}
+ {% trans "Edit media" %}
+ {% else %}
+ {% trans "New media" %}
+ {% endif %}
+{% endblock %}
+
+{% block content %}
+
+ {% if mediafile %}
+ {% trans "Edit media" %}
+ {% else %}
+ {% trans "New media" %}
+ {% endif %}
+
+ {% trans "Back to overview" %}
+
+