diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini index 28be5f34..a296f0c1 100644 --- a/mediagoblin/config_spec.ini +++ b/mediagoblin/config_spec.ini @@ -24,6 +24,11 @@ email_sender_address = string(default="notice@mediagoblin.example.org") # Set to false to disable registrations allow_registration = boolean(default=True) +# tag parsing +tags_delimiter = string(default=",") +tags_case_sensitive = boolean(default=False) +tags_max_length = integer(default=50) + # By default not set, but you might want something like: # "%(here)s/user_dev/templates/" local_templates = string() diff --git a/mediagoblin/db/indexes.py b/mediagoblin/db/indexes.py index a832e013..30d43c98 100644 --- a/mediagoblin/db/indexes.py +++ b/mediagoblin/db/indexes.py @@ -90,6 +90,21 @@ MEDIAENTRY_INDEXES = { # Indexing on uploaders and when media entries are created. # Used for showing a user gallery, etc. 'index': [('uploader', ASCENDING), + ('created', DESCENDING)]}, + + 'state_uploader_tags_created': { + # Indexing on processed?, media uploader, associated tags, and timestamp + # Used for showing media items matching a tag search, most recent first. + 'index': [('state', ASCENDING), + ('uploader', ASCENDING), + ('tags.slug', DESCENDING), + ('created', DESCENDING)]}, + + 'state_tags_created': { + # Indexing on processed?, media tags, and timestamp (across all users) + # This is used for a front page tag search. + 'index': [('state', ASCENDING), + ('tags.slug', DESCENDING), ('created', DESCENDING)]}} diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index bad15aca..4ef2d928 100644 --- a/mediagoblin/db/models.py +++ b/mediagoblin/db/models.py @@ -184,7 +184,7 @@ class MediaEntry(Document): 'media_type': unicode, 'media_data': dict, # extra data relevant to this media_type 'plugin_data': dict, # plugins can dump stuff here. - 'tags': [unicode], + 'tags': [dict], 'state': unicode, # For now let's assume there can only be one main file queued diff --git a/mediagoblin/edit/forms.py b/mediagoblin/edit/forms.py index 0ed52af1..a1783a72 100644 --- a/mediagoblin/edit/forms.py +++ b/mediagoblin/edit/forms.py @@ -16,6 +16,7 @@ import wtforms +from mediagoblin.util import tag_length_validator, TOO_LONG_TAG_WARNING class EditForm(wtforms.Form): @@ -26,6 +27,9 @@ class EditForm(wtforms.Form): 'Slug', [wtforms.validators.Required(message="The slug can't be empty")]) description = wtforms.TextAreaField('Description of this work') + tags = wtforms.TextField( + 'Tags', + [tag_length_validator]) class EditProfileForm(wtforms.Form): bio = wtforms.TextAreaField('Bio', diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index f372fbb9..5cbaadb5 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -16,10 +16,13 @@ from webob import exc +from string import split from mediagoblin import messages +from mediagoblin import mg_globals from mediagoblin.util import ( - render_to_response, redirect, cleaned_markdown_conversion) + render_to_response, redirect, clean_html, convert_to_tag_list_of_dicts, + media_tags_as_string, cleaned_markdown_conversion) from mediagoblin.edit import forms from mediagoblin.edit.lib import may_edit_media from mediagoblin.decorators import require_active_login, get_user_media_entry @@ -34,7 +37,8 @@ def edit_media(request, media): form = forms.EditForm(request.POST, title = media['title'], slug = media['slug'], - description = media['description']) + description = media['description'], + tags = media_tags_as_string(media['tags'])) if request.method == 'POST' and form.validate(): # Make sure there isn't already a MediaEntry with such a slug @@ -50,7 +54,9 @@ def edit_media(request, media): else: media['title'] = request.POST['title'] media['description'] = request.POST.get('description') - + media['tags'] = convert_to_tag_list_of_dicts( + request.POST.get('tags')) + media['description_html'] = cleaned_markdown_conversion( media['description']) diff --git a/mediagoblin/submit/forms.py b/mediagoblin/submit/forms.py index 3fd9ea49..1a5a7f4e 100644 --- a/mediagoblin/submit/forms.py +++ b/mediagoblin/submit/forms.py @@ -16,6 +16,7 @@ import wtforms +from mediagoblin.util import tag_length_validator, TOO_LONG_TAG_WARNING class SubmitStartForm(wtforms.Form): @@ -24,3 +25,6 @@ class SubmitStartForm(wtforms.Form): [wtforms.validators.Length(min=0, max=500)]) description = wtforms.TextAreaField('Description of this work') file = wtforms.FileField('File') + tags = wtforms.TextField( + 'Tags', + [tag_length_validator]) diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index 1848f5e5..87e57dda 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -16,11 +16,13 @@ from os.path import splitext from cgi import FieldStorage +from string import split from werkzeug.utils import secure_filename from mediagoblin.util import ( - render_to_response, redirect, cleaned_markdown_conversion) + render_to_response, redirect, cleaned_markdown_conversion, \ + convert_to_tag_list_of_dicts) from mediagoblin.decorators import require_active_login from mediagoblin.submit import forms as submit_forms, security from mediagoblin.process_media import process_media_initial @@ -59,6 +61,10 @@ def submit_start(request): entry['media_type'] = u'image' # heh entry['uploader'] = request.user['_id'] + # Process the user's folksonomy "tags" + entry['tags'] = convert_to_tag_list_of_dicts( + request.POST.get('tags')) + # Save, just so we can get the entry id for the sake of using # it to generate the file path entry.save(validate=False) diff --git a/mediagoblin/templates/mediagoblin/submit/start.html b/mediagoblin/templates/mediagoblin/submit/start.html index 50c86afe..7bacb552 100644 --- a/mediagoblin/templates/mediagoblin/submit/start.html +++ b/mediagoblin/templates/mediagoblin/submit/start.html @@ -25,6 +25,7 @@
Sorry, no such media found.
diff --git a/mediagoblin/templates/mediagoblin/utils/tags.html b/mediagoblin/templates/mediagoblin/utils/tags.html new file mode 100644 index 00000000..94c4cf69 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/utils/tags.html @@ -0,0 +1,25 @@ +{# +# 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