Merge remote-tracking branch 'origin/master' into is315
This commit is contained in:
commit
78c0744077
28
docs/git.rst
28
docs/git.rst
@ -108,8 +108,8 @@ Contributing changes
|
||||
--------------------
|
||||
|
||||
Slartibartfast from the planet Magrathea far off in the universe has
|
||||
decided that he is bored with fjords and wants to fix issue 42 and
|
||||
send us the changes.
|
||||
decided that he is bored with fjords and wants to fix issue 42 (the
|
||||
meaning of life bug) and send us the changes.
|
||||
|
||||
Slartibartfast has cloned the MediaGoblin repository and his clone
|
||||
lives on gitorious.
|
||||
@ -125,18 +125,18 @@ Slartibartfast does the following:
|
||||
git fetch --all -p
|
||||
|
||||
2. Creates a branch from the tip of the MediaGoblin repository (the
|
||||
remote is named ``gmg``) master branch called ``issue_42``::
|
||||
remote is named ``gmg``) master branch called ``bug42_meaning_of_life``::
|
||||
|
||||
git checkout -b issue_42 gmg/master
|
||||
git checkout -b bug42_meaning_of_life gmg/master
|
||||
|
||||
3. Slartibartfast works hard on his changes in the ``issue_42``
|
||||
3. Slartibartfast works hard on his changes in the ``bug42_meaning_of_life``
|
||||
branch. When done, he wants to notify us that he has made changes
|
||||
he wants us to see.
|
||||
|
||||
4. Slartibartfast pushes his changes to his clone (the remote is named
|
||||
``origin``)::
|
||||
|
||||
git push origin issue_42 --set-upstream
|
||||
git push origin bug42_meaning_of_life --set-upstream
|
||||
|
||||
5. Slartibartfast adds a comment to issue 42 with the url for his
|
||||
repository and the name of the branch he put the code in. He also
|
||||
@ -155,19 +155,19 @@ He runs the unit tests and discovers there's a bug in the code!
|
||||
|
||||
Then he does this:
|
||||
|
||||
1. He checks out the ``issue_42`` branch::
|
||||
1. He checks out the ``bug42_meaning_of_life`` branch::
|
||||
|
||||
git checkout issue_42
|
||||
git checkout bug42_meaning_of_life
|
||||
|
||||
2. He fixes the bug and checks it into the ``issue_42`` branch.
|
||||
2. He fixes the bug and checks it into the ``bug42_meaning_of_life`` branch.
|
||||
|
||||
3. He pushes his changes to his clone (the remote is named ``origin``)::
|
||||
|
||||
git push origin issue_42
|
||||
git push origin bug42_meaning_of_life
|
||||
|
||||
4. He adds another comment to issue 42 explaining about the mistake
|
||||
and how he fixed it and that he's pushed the new change to the
|
||||
``issue_42`` branch of his publicly available clone.
|
||||
``bug42_meaning_of_life`` branch of his publicly available clone.
|
||||
|
||||
|
||||
What happens next
|
||||
@ -180,7 +180,7 @@ request with his changes and explains what they are.
|
||||
Later, someone checks out his code and finds a problem with it. He
|
||||
adds a comment to the issue tracker specifying the problem and asks
|
||||
Slartibartfast to fix it. Slartibartfst goes through the above steps
|
||||
again, fixes the issue, pushes it to his ``issue_42`` branch and adds
|
||||
again, fixes the issue, pushes it to his ``bug42_meaning_of_life`` branch and adds
|
||||
another comment to the issue tracker about how he fixed it.
|
||||
|
||||
Later, someone checks out his code and is happy with it. Someone
|
||||
@ -192,8 +192,8 @@ Slartibartfast is notified of this. Slartibartfast does a::
|
||||
git fetch --all
|
||||
|
||||
The changes show up in the ``master`` branch of the ``gmg`` remote.
|
||||
Slartibartfast now deletes his ``issue_42`` branch because he doesn't
|
||||
need it anymore.
|
||||
Slartibartfast now deletes his ``bug42_meaning_of_life`` branch
|
||||
because he doesn't need it anymore.
|
||||
|
||||
|
||||
How to learn git
|
||||
|
@ -136,7 +136,7 @@ This is fine in development, but if you want to actually run celery
|
||||
separately for testing (or deployment purposes), you'll want to run
|
||||
the server independently::
|
||||
|
||||
./bin/paster serve server.ini --reload
|
||||
./bin/paster serve paste.ini --reload
|
||||
|
||||
|
||||
Running celeryd
|
||||
@ -158,7 +158,7 @@ Running the test suite
|
||||
|
||||
Run::
|
||||
|
||||
./bin/nosetests
|
||||
./runtests.sh
|
||||
|
||||
|
||||
Running a shell
|
||||
|
@ -27,4 +27,4 @@ else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CELERY_ALWAYS_EAGER=true $PASTER serve server.ini --reload
|
||||
CELERY_ALWAYS_EAGER=true $PASTER serve paste.ini --reload
|
||||
|
@ -14,6 +14,8 @@
|
||||
# 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/>.
|
||||
|
||||
from mediagoblin.util import cleaned_markdown_conversion
|
||||
|
||||
from mongokit import DocumentMigration
|
||||
|
||||
|
||||
@ -33,5 +35,19 @@ class MediaEntryMigration(DocumentMigration):
|
||||
self.collection.update(
|
||||
self.target, self.update, multi=True, safe=True)
|
||||
|
||||
def allmigration02_add_description_html(self):
|
||||
"""
|
||||
Now that we can have rich descriptions via Markdown, we should
|
||||
update all existing entries to record the rich description versions.
|
||||
"""
|
||||
self.target = {'description_html': {'$exists': False}}
|
||||
|
||||
if not self.status:
|
||||
for doc in self.collection.find(self.target):
|
||||
self.update = {
|
||||
'$set': {
|
||||
'description_html': cleaned_markdown_conversion(
|
||||
doc['description'])}}
|
||||
|
||||
|
||||
MIGRATE_CLASSES = ['MediaEntry']
|
||||
|
@ -75,7 +75,8 @@ class MediaEntry(Document):
|
||||
'title': unicode,
|
||||
'slug': unicode,
|
||||
'created': datetime.datetime,
|
||||
'description': unicode,
|
||||
'description': unicode, # May contain markdown/up
|
||||
'description_html': unicode, # May contain plaintext, or HTML
|
||||
'media_type': unicode,
|
||||
'media_data': dict, # extra data relevant to this media_type
|
||||
'plugin_data': dict, # plugins can dump stuff here.
|
||||
|
@ -17,11 +17,13 @@
|
||||
|
||||
from webob import exc
|
||||
|
||||
from mediagoblin.util import render_to_response, redirect
|
||||
from mediagoblin.util import render_to_response, redirect, clean_html
|
||||
from mediagoblin.edit import forms
|
||||
from mediagoblin.edit.lib import may_edit_media
|
||||
from mediagoblin.decorators import require_active_login, get_user_media_entry
|
||||
|
||||
import markdown
|
||||
|
||||
|
||||
@get_user_media_entry
|
||||
@require_active_login
|
||||
@ -47,7 +49,14 @@ def edit_media(request, media):
|
||||
u'An entry with that slug already exists for this user.')
|
||||
else:
|
||||
media['title'] = request.POST['title']
|
||||
media['description'] = request.POST['description']
|
||||
media['description'] = request.POST.get('description')
|
||||
|
||||
md = markdown.Markdown(
|
||||
safe_mode = 'escape')
|
||||
media['description_html'] = clean_html(
|
||||
md.convert(
|
||||
media['description']))
|
||||
|
||||
media['slug'] = request.POST['slug']
|
||||
media.save()
|
||||
|
||||
|
@ -19,7 +19,8 @@ from cgi import FieldStorage
|
||||
|
||||
from werkzeug.utils import secure_filename
|
||||
|
||||
from mediagoblin.util import render_to_response, redirect
|
||||
from mediagoblin.util import (
|
||||
render_to_response, redirect, cleaned_markdown_conversion)
|
||||
from mediagoblin.decorators import require_active_login
|
||||
from mediagoblin.submit import forms as submit_forms, security
|
||||
from mediagoblin.process_media import process_media_initial
|
||||
@ -46,8 +47,14 @@ def submit_start(request):
|
||||
|
||||
# create entry and save in database
|
||||
entry = request.db.MediaEntry()
|
||||
entry['title'] = request.POST['title'] or unicode(splitext(filename)[0])
|
||||
entry['title'] = (
|
||||
request.POST['title']
|
||||
or unicode(splitext(filename)[0]))
|
||||
|
||||
entry['description'] = request.POST.get('description')
|
||||
entry['description_html'] = cleaned_markdown_conversion(
|
||||
entry['description'])
|
||||
|
||||
entry['media_type'] = u'image' # heh
|
||||
entry['uploader'] = request.user['_id']
|
||||
|
||||
|
@ -25,7 +25,9 @@
|
||||
</h1>
|
||||
<img class="media_image" src="{{ request.app.public_store.file_url(
|
||||
media.media_files.main) }}" />
|
||||
<p>{{ media.description }}</p>
|
||||
{% autoescape False %}
|
||||
<p>{{ media.description_html }}</p>
|
||||
{% endautoescape %}
|
||||
<p>Uploaded on
|
||||
{{ "%4d-%02d-%02d"|format(media.created.year,
|
||||
media.created.month, media.created.day) }}
|
||||
|
@ -242,17 +242,69 @@ def test_authentication_views(test_app):
|
||||
test_user.save()
|
||||
|
||||
# Get login
|
||||
# ---------
|
||||
test_app.get('/auth/login/')
|
||||
# Make sure it rendered with the appropriate template
|
||||
assert util.TEMPLATE_TEST_CONTEXT.has_key(
|
||||
'mediagoblin/auth/login.html')
|
||||
|
||||
# Log in as that user
|
||||
# Failed login - blank form
|
||||
# -------------------------
|
||||
util.clear_test_template_context()
|
||||
response = test_app.post('/auth/login/')
|
||||
context = util.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/login.html']
|
||||
form = context['login_form']
|
||||
assert form.username.errors == [u'This field is required.']
|
||||
assert form.password.errors == [u'This field is required.']
|
||||
|
||||
# Failed login - blank user
|
||||
# -------------------------
|
||||
util.clear_test_template_context()
|
||||
response = test_app.post(
|
||||
'/auth/login/', {
|
||||
'password': u'toast'})
|
||||
context = util.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/login.html']
|
||||
form = context['login_form']
|
||||
assert form.username.errors == [u'This field is required.']
|
||||
|
||||
# Failed login - blank password
|
||||
# -----------------------------
|
||||
util.clear_test_template_context()
|
||||
response = test_app.post(
|
||||
'/auth/login/', {
|
||||
'username': u'chris'})
|
||||
context = util.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/login.html']
|
||||
form = context['login_form']
|
||||
assert form.password.errors == [u'This field is required.']
|
||||
|
||||
# Failed login - bad user
|
||||
# -----------------------
|
||||
util.clear_test_template_context()
|
||||
response = test_app.post(
|
||||
'/auth/login/', {
|
||||
'username': u'steve',
|
||||
'password': 'toast'})
|
||||
context = util.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/login.html']
|
||||
assert context['login_failed']
|
||||
|
||||
# Failed login - bad password
|
||||
# ---------------------------
|
||||
util.clear_test_template_context()
|
||||
response = test_app.post(
|
||||
'/auth/login/', {
|
||||
'username': u'chris',
|
||||
'password': 'jam'})
|
||||
context = util.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/login.html']
|
||||
assert context['login_failed']
|
||||
|
||||
# Successful login
|
||||
# ----------------
|
||||
util.clear_test_template_context()
|
||||
response = test_app.post(
|
||||
'/auth/login/', {
|
||||
'username': u'chris',
|
||||
'password': 'toast'})
|
||||
|
||||
# User should be redirected
|
||||
response.follow()
|
||||
assert_equal(
|
||||
urlparse.urlsplit(response.location)[2],
|
||||
@ -260,10 +312,38 @@ def test_authentication_views(test_app):
|
||||
assert util.TEMPLATE_TEST_CONTEXT.has_key(
|
||||
'mediagoblin/root.html')
|
||||
|
||||
# Make sure we're in the session or something
|
||||
session = util.TEMPLATE_TEST_CONTEXT['mediagoblin/root.html']['request'].session
|
||||
# Make sure user is in the session
|
||||
context = util.TEMPLATE_TEST_CONTEXT['mediagoblin/root.html']
|
||||
session = context['request'].session
|
||||
assert session['user_id'] == unicode(test_user['_id'])
|
||||
|
||||
# Log out as that user
|
||||
# Make sure we're not in the session
|
||||
# Successful logout
|
||||
# -----------------
|
||||
util.clear_test_template_context()
|
||||
response = test_app.get('/auth/logout/')
|
||||
|
||||
# Should be redirected to index page
|
||||
response.follow()
|
||||
assert_equal(
|
||||
urlparse.urlsplit(response.location)[2],
|
||||
'/')
|
||||
assert util.TEMPLATE_TEST_CONTEXT.has_key(
|
||||
'mediagoblin/root.html')
|
||||
|
||||
# Make sure the user is not in the session
|
||||
context = util.TEMPLATE_TEST_CONTEXT['mediagoblin/root.html']
|
||||
session = context['request'].session
|
||||
assert session.has_key('user_id') == False
|
||||
|
||||
# User is redirected to custom URL if POST['next'] is set
|
||||
# -------------------------------------------------------
|
||||
util.clear_test_template_context()
|
||||
response = test_app.post(
|
||||
'/auth/login/', {
|
||||
'username': u'chris',
|
||||
'password': 'toast',
|
||||
'next' : '/u/chris/'})
|
||||
assert_equal(
|
||||
urlparse.urlsplit(response.location)[2],
|
||||
'/u/chris/')
|
||||
|
||||
|
@ -30,7 +30,7 @@ from mediagoblin.db.open import setup_connection_and_db_from_config
|
||||
|
||||
MEDIAGOBLIN_TEST_DB_NAME = '__mediagoblinunittests__'
|
||||
TEST_SERVER_CONFIG = pkg_resources.resource_filename(
|
||||
'mediagoblin.tests', 'test_server.ini')
|
||||
'mediagoblin.tests', 'test_paste.ini')
|
||||
TEST_APP_CONFIG = pkg_resources.resource_filename(
|
||||
'mediagoblin.tests', 'test_mgoblin_app.ini')
|
||||
TEST_USER_DEV = pkg_resources.resource_filename(
|
||||
|
@ -111,7 +111,7 @@ def atom_feed(request):
|
||||
|
||||
for entry in cursor:
|
||||
feed.add(entry.get('title'),
|
||||
entry.get('description'),
|
||||
entry.get('description_html'),
|
||||
content_type='html',
|
||||
author=request.matchdict['user'],
|
||||
updated=entry.get('created'),
|
||||
|
@ -29,11 +29,11 @@ import jinja2
|
||||
import translitcodec
|
||||
from webob import Response, exc
|
||||
from lxml.html.clean import Cleaner
|
||||
import markdown
|
||||
|
||||
from mediagoblin import mg_globals
|
||||
from mediagoblin.db.util import ObjectId
|
||||
|
||||
|
||||
TESTS_ENABLED = False
|
||||
def _activate_testing():
|
||||
"""
|
||||
@ -98,7 +98,7 @@ def get_jinja_env(template_loader, locale):
|
||||
|
||||
template_env = jinja2.Environment(
|
||||
loader=template_loader, autoescape=True,
|
||||
extensions=['jinja2.ext.i18n'])
|
||||
extensions=['jinja2.ext.i18n', 'jinja2.ext.autoescape'])
|
||||
|
||||
template_env.install_gettext_callables(
|
||||
mg_globals.translations.gettext,
|
||||
@ -376,6 +376,16 @@ def clean_html(html):
|
||||
return HTML_CLEANER.clean_html(html)
|
||||
|
||||
|
||||
MARKDOWN_INSTANCE = markdown.Markdown(safe_mode='escape')
|
||||
|
||||
|
||||
def cleaned_markdown_conversion(text):
|
||||
"""
|
||||
Take a block of text, run it through MarkDown, and clean its HTML.
|
||||
"""
|
||||
return clean_html(MARKDOWN_INSTANCE.convert(text))
|
||||
|
||||
|
||||
SETUP_GETTEXTS = {}
|
||||
|
||||
def setup_gettext(locale):
|
||||
|
Loading…
x
Reference in New Issue
Block a user