diff options
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | .tx/config | 8 | ||||
-rw-r--r-- | babel.ini | 2 | ||||
-rw-r--r-- | mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo | bin | 0 -> 602 bytes | |||
-rw-r--r-- | mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po | 25 | ||||
-rw-r--r-- | mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po | 35 | ||||
-rw-r--r-- | mediagoblin/process_media/__init__.py | 13 | ||||
-rw-r--r-- | mediagoblin/storage.py | 86 | ||||
-rw-r--r-- | mediagoblin/util.py | 2 | ||||
-rw-r--r-- | setup.py | 2 |
10 files changed, 161 insertions, 15 deletions
@@ -10,7 +10,8 @@ mediagoblin.egg-info *.pyo docs/_build/ user_dev/ -mediagoblin_user.ini +paste_local.ini +mediagoblin_local.ini server-log.txt *~ *.swp diff --git a/.tx/config b/.tx/config new file mode 100644 index 00000000..711b5d94 --- /dev/null +++ b/.tx/config @@ -0,0 +1,8 @@ +[mediagoblin.mediagoblin] +file_filter = mediagoblin/i18n/<lang>/LC_MESSAGES/mediagoblin.po +source_file = mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po +source_lang = en + +[main] +host = https://www.transifex.net + @@ -10,4 +10,4 @@ encoding = utf-8 # # Extraction from JavaScript files # [javascript: mediagoblin/static/js/**.js] -# extract_messages = $._, jQuery._
\ No newline at end of file +# extract_messages = $._, jQuery._ diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo Binary files differnew file mode 100644 index 00000000..ba625623 --- /dev/null +++ b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po new file mode 100644 index 00000000..715757fb --- /dev/null +++ b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po @@ -0,0 +1,25 @@ +# Translations template for PROJECT. +# Copyright (C) 2011 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# +# <cwebber@dustycloud.org>, 2011. +msgid "" +msgstr "" +"Project-Id-Version: GNU MediaGoblin\n" +"Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n" +"POT-Creation-Date: 2011-08-06 23:01-0500\n" +"PO-Revision-Date: 2011-08-07 14:06+0000\n" +"Last-Translator: cwebber <cwebber@dustycloud.org>\n" +"Language-Team: German (http://www.transifex.net/projects/p/mediagoblin/team/de/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 0.9.6\n" +"Language: de\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +#: mediagoblin/templates/mediagoblin/root.html:21 +msgid "Welcome to GNU MediaGoblin!" +msgstr "Willkommen bei GNU MediaGoblin!" + + diff --git a/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po new file mode 100644 index 00000000..67830c2e --- /dev/null +++ b/mediagoblin/i18n/en/LC_MESSAGES/mediagoblin.po @@ -0,0 +1,35 @@ +# Translations template for GNU MediaGoblin. +# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: GNU MediaGoblin\n" +"POT-Creation-Date: 2011-08-06 23:01-0500\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 0.9.6\n" + +#: mediagoblin/templates/mediagoblin/root.html:21 +msgid "Welcome to GNU MediaGoblin!" +msgstr "" + diff --git a/mediagoblin/process_media/__init__.py b/mediagoblin/process_media/__init__.py index 125b24e0..8e12ca4d 100644 --- a/mediagoblin/process_media/__init__.py +++ b/mediagoblin/process_media/__init__.py @@ -19,6 +19,7 @@ from mediagoblin.db.util import ObjectId from celery.task import task from mediagoblin import mg_globals as mgg +from contextlib import contextmanager THUMB_SIZE = 180, 180 @@ -31,6 +32,12 @@ def create_pub_filepath(entry, filename): unicode(entry['_id']), filename]) +@contextmanager +def closing(callback): + try: + yield callback + finally: + pass @task def process_media_initial(media_id): @@ -53,7 +60,7 @@ def process_media_initial(media_id): thumb_filepath = create_pub_filepath(entry, 'thumbnail.jpg') thumb_file = mgg.public_store.get_file(thumb_filepath, 'w') - with thumb_file: + with closing(thumb_file): thumb.save(thumb_file, "JPEG", quality=90) """ @@ -73,7 +80,7 @@ def process_media_initial(media_id): medium_filepath = create_pub_filepath(entry, 'medium.jpg') medium_file = mgg.public_store.get_file(medium_filepath, 'w') - with medium_file: + with closing(medium_file): medium.save(medium_file, "JPEG", quality=90) medium_processed = True @@ -84,7 +91,7 @@ def process_media_initial(media_id): with queued_file: original_filepath = create_pub_filepath(entry, queued_filepath[-1]) - with mgg.public_store.get_file(original_filepath, 'wb') as original_file: + with closing(mgg.public_store.get_file(original_filepath, 'wb')) as original_file: original_file.write(queued_file.read()) mgg.queue_store.delete_file(queued_filepath) diff --git a/mediagoblin/storage.py b/mediagoblin/storage.py index 5d6faa4c..e449eda3 100644 --- a/mediagoblin/storage.py +++ b/mediagoblin/storage.py @@ -19,6 +19,7 @@ import re import shutil import urlparse import uuid +import cloudfiles from werkzeug.utils import secure_filename @@ -28,11 +29,21 @@ from mediagoblin import util # Errors ######## -class Error(Exception): pass -class InvalidFilepath(Error): pass -class NoWebServing(Error): pass -class NotImplementedError(Error): pass +class Error(Exception): + pass + + +class InvalidFilepath(Error): + pass + + +class NoWebServing(Error): + pass + + +class NotImplementedError(Error): + pass ############################################### @@ -117,7 +128,7 @@ class StorageInterface(object): Eg, if the filename doesn't exist: >>> storage_handler.get_unique_filename(['dir1', 'dir2', 'fname.jpg']) [u'dir1', u'dir2', u'fname.jpg'] - + But if a file does exist, let's get one back with at uuid tacked on: >>> storage_handler.get_unique_filename(['dir1', 'dir2', 'fname.jpg']) [u'dir1', u'dir2', u'd02c3571-dd62-4479-9d62-9e3012dada29-fname.jpg'] @@ -184,7 +195,7 @@ class BasicFileStorage(StorageInterface): """ return os.path.join( self.base_dir, *clean_listy_filepath(filepath)) - + def file_exists(self, filepath): return os.path.exists(self._resolve_filepath(filepath)) @@ -216,6 +227,65 @@ class BasicFileStorage(StorageInterface): return self._resolve_filepath(filepath) +class CloudFilesStorage(StorageInterface): + def __init__(self, **kwargs): + self.param_container = kwargs.get('cloudfiles_container') + self.param_user = kwargs.get('cloudfiles_user') + self.param_api_key = kwargs.get('cloudfiles_api_key') + self.param_host = kwargs.get('cloudfiles_host') + self.param_use_servicenet = kwargs.get('cloudfiles_use_servicenet') + + if not self.param_host: + print('No CloudFiles host URL specified, ' + 'defaulting to Rackspace US') + + self.connection = cloudfiles.get_connection( + username=self.param_user, + api_key=self.param_api_key, + servicenet=True if self.param_use_servicenet == 'true' or \ + self.param_use_servicenet == True else False) + + if not self.param_container == \ + self.connection.get_container(self.param_container): + self.container = self.connection.create_container( + self.param_container) + self.container.make_public( + ttl=60 * 60 * 2) + else: + self.container = self.connection.get_container( + self.param_container) + + def _resolve_filepath(self, filepath): + return '/'.join( + clean_listy_filepath(filepath)) + + def file_exists(self, filepath): + try: + object = self.container.get_object( + self._resolve_filepath(filepath)) + return True + except cloudfiles.errors.NoSuchObject: + return False + + def get_file(self, filepath, mode='r'): + try: + obj = self.container.get_object( + self._resolve_filepath(filepath)) + except cloudfiles.errors.NoSuchObject: + obj = self.container.create_object( + self._resolve_filepath(filepath)) + + return obj + + def delete_file(self, filepath): + # TODO: Also delete unused directories if empty (safely, with + # checks to avoid race conditions). + self.container.delete_object(filepath) + + def file_url(self, filepath): + return self.get_file(filepath).public_uri() + + ########### # Utilities ########### @@ -283,7 +353,7 @@ def storage_system_from_config(paste_config, storage_prefix): for key, value in paste_config.iteritems() if prefix_re.match(key)]) - if config_params.has_key('storage_class'): + if 'storage_class' in config_params: storage_class = config_params['storage_class'] config_params.pop('storage_class') else: @@ -291,5 +361,3 @@ def storage_system_from_config(paste_config, storage_prefix): storage_class = util.import_component(storage_class) return storage_class(**config_params) - - diff --git a/mediagoblin/util.py b/mediagoblin/util.py index 5880f856..c9f4a0ac 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -300,7 +300,7 @@ def send_email(from_addr, to_addrs, subject, message_body): TRANSLATIONS_PATH = pkg_resources.resource_filename( - 'mediagoblin', 'translations') + 'mediagoblin', 'i18n') def locale_to_lower_upper(locale): @@ -44,6 +44,7 @@ setup( 'webtest', 'ConfigObj', 'Markdown', + 'python-cloudfiles', ## For now we're expecting that users will install this from ## their package managers. # 'lxml', @@ -52,6 +53,7 @@ setup( entry_points = """\ [console_scripts] gmg = mediagoblin.gmg_commands:main_cli + pybabel = mediagoblin.babel.messages.frontend:main [paste.app_factory] app = mediagoblin.app:paste_app_factory |