This was a quick update, I mostly worked on the transition from using the old
authortilly-Q <nattilypigeonfowl@gmail.com>
Sun, 8 Sep 2013 22:26:37 +0000 (18:26 -0400)
committertilly-Q <nattilypigeonfowl@gmail.com>
Sun, 8 Sep 2013 22:26:37 +0000 (18:26 -0400)
User table columns (is_admin, status, email_verified) and making sure that
their functionality is instead completely handled by privileges. I also worked
on the meta pages which I hope to finish soon. I set up migrations to ensure
the default privileges are given to users that should have them. Lastly, I made
it so that banned users can log out.

===============================================================================
    Made Sure the Vestigial Columns of the User Table were not being Used
===============================================================================
--\ mediagoblin/auth/views.py
--\ mediagoblin/db/models.py
--\ mediagoblin/templates/mediagoblin/base.html
--\ mediagoblin/templates/mediagoblin/moderation/user.html
--\ mediagoblin/templates/mediagoblin/user_pages/collection_lis$
--\ mediagoblin/templates/mediagoblin/user_pages/user.html
--\ mediagoblin/tests/test_auth.py
--\ mediagoblin/tests/test_persona.py
--\ mediagoblin/user_pages/views.py

===============================================================================
    Wrote the Migrations to Set up the Default Privileges
===============================================================================
--\ mediagoblin/db/migrations.py
--\ mediagoblin/gmg_commands/users.py

===============================================================================
    Work on the Meta Pages
===============================================================================
--\ mediagoblin/meta/routing.py
--\ mediagoblin/meta/views.py
--\ mediagoblin/static/css/base.css
--\ mediagoblin/templates/mediagoblin/meta/terms_of_service.html

===============================================================================
    Small Changes
===============================================================================
--\ mediagoblin/templates/mediagoblin/base.html
--| Benevolently made it so that banned users can log out

===============================================================================
X   X   X   X   X   X   X   X   X   X   X   X   X   X   X   X   X   X   X   X
===============================================================================

15 files changed:
mediagoblin/auth/views.py
mediagoblin/db/migrations.py
mediagoblin/db/models.py
mediagoblin/gmg_commands/users.py
mediagoblin/meta/routing.py
mediagoblin/meta/views.py
mediagoblin/static/css/base.css
mediagoblin/templates/mediagoblin/base.html
mediagoblin/templates/mediagoblin/meta/terms_of_service.html
mediagoblin/templates/mediagoblin/moderation/user.html
mediagoblin/templates/mediagoblin/user_pages/collection_list.html
mediagoblin/templates/mediagoblin/user_pages/user.html
mediagoblin/tests/test_auth.py
mediagoblin/tests/test_persona.py
mediagoblin/user_pages/views.py

index 7d95b81a88fb463f6a5b626ce8f15e4ba0cee3dd..5e2a2af09b84ed1275e54e27d008b524525b527f 100644 (file)
@@ -150,9 +150,7 @@ def verify_email(request):
 
     user = User.query.filter_by(id=int(token)).first()
 
-    if user and user.email_verified is False:
-        user.status = u'active'
-        user.email_verified = True
+    if user and user.has_privilege(u'active') is False:
         user.verification_key = None
         user.all_privileges.append(
             Privilege.query.filter(
@@ -191,7 +189,7 @@ def resend_activation(request):
 
         return redirect(request, 'mediagoblin.auth.login')
 
-    if request.user.email_verified:
+    if request.user.has_privilege(u'active'):
         messages.add_message(
             request,
             messages.ERROR,
@@ -256,7 +254,7 @@ def forgot_password(request):
         success_message=_("An email has been sent with instructions "
                           "on how to change your password.")
 
-    if user and not(user.email_verified and user.status == 'active'):
+    if user and not(user.has_privilege(u'active')):
         # Don't send reminder because user is inactive or has no verified email
         messages.add_message(request,
             messages.WARNING,
@@ -312,8 +310,8 @@ def verify_forgot_password(request):
         return redirect(
             request, 'index')
 
-    # check if user active and has email verified
-    if user.email_verified and user.status == 'active':
+    # check if user active
+    if user.has_privilege(u'active'):
 
         cp_form = auth_forms.ChangePassForm(formdata_vars)
 
@@ -333,13 +331,13 @@ def verify_forgot_password(request):
                 'mediagoblin/auth/change_fp.html',
                 {'cp_form': cp_form,})
 
-    if not user.email_verified:
+    if not user.has_privilege(u'active'):
         messages.add_message(
             request, messages.ERROR,
             _('You need to verify your email before you can reset your'
               ' password.'))
 
-    if not user.status == 'active':
+    if not user.has_privilege(u'active'):
         messages.add_message(
             request, messages.ERROR,
             _('You are no longer an active user. Please contact the system'
index 6659feb393398e43c59269922fb63dae1eb43d38..1c0a929109ecd4b3ed872e6acca6b5f519339948 100644 (file)
@@ -29,7 +29,8 @@ from migrate.changeset.constraint import UniqueConstraint
 from mediagoblin.db.extratypes import JSONEncoded
 from mediagoblin.db.migration_tools import RegisterMigration, inspect_table
 from mediagoblin.db.models import (MediaEntry, Collection, User,
-                                   MediaComment, Privilege, ReportBase)
+                                   MediaComment, Privilege, ReportBase,
+                                   FOUNDATIONS)
 
 MIGRATIONS = {}
 
@@ -531,6 +532,40 @@ def create_moderation_tables(db):
     UserBan_v0.__table__.create(db.bind)
     Privilege_v0.__table__.create(db.bind)
     PrivilegeUserAssociation_v0.__table__.create(db.bind)
+
     db.commit()
 
+    for parameters in FOUNDATIONS[Privilege]:
+        p = Privilege(**parameters)
+        p.save()
+
 
+@RegisterMigration(16, MIGRATIONS)
+def update_user_privilege_columns(db):
+    metadata = MetaData(bind=db.bind)
+    default_privileges = Privilege.query.filter(
+        Privilege.privilege_name !=u'admin').filter(
+        Privilege.privilege_name !=u'moderator').filter(
+        Privilege.privilege_name !=u'active').all()
+    admin_privilege = Privilege.query.filter(
+        Privilege.privilege_name ==u'admin').first()
+    active_privilege = Privilege.query.filter(
+        Privilege.privilege_name ==u'active').first()
+    for inactive_user in User.query.filter(
+        User.status!=u'active').filter(
+        User.is_admin==False).all():
+
+        inactive_user.all_privileges = default_privileges
+        inactive_user.save()
+    for user in User.query.filter(
+        User.status==u'active').filter(
+        User.is_admin==False).all():
+
+        user.all_privileges = default_privileges + [active_privilege]
+        user.save()
+    for admin_user in User.query.filter(
+        User.is_admin==True).all():
+
+        admin_user.all_privileges = default_privileges + [
+            admin_privilege, active_privilege]
+        admin_user.save()
index f25dc32ca2d52bf6636ef1c6c97b5e7b0daa8e97..5b77a85d49be6e41a75bd43d919fa4f350fb8bf5 100644 (file)
@@ -81,8 +81,8 @@ class User(Base, UserMixin):
         return '<{0} #{1} {2} {3} "{4}">'.format(
                 self.__class__.__name__,
                 self.id,
-                'verified' if self.email_verified else 'non-verified',
-                'admin' if self.is_admin else 'user',
+                'verified' if self.has_privilege(u'active') else 'non-verified',
+                'admin' if self.has_privilege(u'admin') else 'user',
                 self.username)
 
     def delete(self, **kwargs):
index d319cef9f0ab9ecca662d2f7d50954b0fb14c820..4a730d9e866756afb0d4ef25274439d6b9a80261 100644 (file)
@@ -53,8 +53,6 @@ def adduser(args):
         entry.username = unicode(args.username.lower())
         entry.email = unicode(args.email)
         entry.pw_hash = auth.gen_password_hash(args.password)
-        entry.status = u'active'
-        entry.email_verified = True
         default_privileges = [
             db.Privilege.query.filter(
                 db.Privilege.privilege_name==u'commenter').one(),
index e61bc06579eabf10a1b05129e356b942af057dec..b74cb52db74cb77629840d49855e6f9636a94cbd 100644 (file)
@@ -15,9 +15,9 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 meta_routes = [
-    ('mediagoblin.meta.code_of_conduct',
-        '/coc/',
-        'mediagoblin.meta.views:code_of_conduct'),
+    ('mediagoblin.meta.terms_of_service',
+        '/tos/',
+        'mediagoblin.meta.views:terms_of_service'),
     ('mediagoblin.meta.reports_panel',
         '/reports/',
         'mediagoblin.meta.views:public_reports_panel'),
index 3df0688cf796ec301554505aaaf78f6eb6c0a5af..79940a22795bae83c5e64fffa749a1c0c8aa8519 100644 (file)
@@ -17,9 +17,9 @@
 from mediagoblin.tools.response import render_to_response
 
 
-def code_of_conduct(request):
+def terms_of_service(request):
     return render_to_response(request,
-        'mediagoblin/meta/code_of_conduct.html',
+        'mediagoblin/meta/terms_of_service.html',
         {})
 
 def public_reports_panel(request):
index 7fcbb93e67b12a3bcf3e255dccb1d7c55f5b1a52..d96106757c56ce0141083290ed6c7c9169aad999 100644 (file)
@@ -663,13 +663,15 @@ table td.user_without_privilege {
     margin-bottom: 10px;
 }
 #code_of_conduct_list li {
-    margin-top:5px;
+    margin:5px 0 15px 25px;
 }
-ol.nested_sublist{
+.nested_sublist {
     margin: 5px 0 10px 25px;
     font-size:80%;
 }
-
+.nested_sublist li {
+    margin-bottom: 10px;
+}
 
 /* ASCII art and code */
 
index 278cebb6e508e7a38ec2dbea9ff2a257133db53f..40cec5f7353c3adfa662712cfad8607165235c99 100644 (file)
@@ -59,7 +59,7 @@
           {% block mediagoblin_header_title %}{% endblock %}
           <div class="header_right">
             {%- if request.user %}
-              {% if request.user and request.user.status == 'active' and not request.user.is_banned() %}
+              {% if request.user and request.user.has_privilege('active') and not request.user.is_banned() %}
 
                 {% set notification_count = get_notification_count(request.user.id) %}
                 {% if notification_count %}
@@ -68,7 +68,7 @@
                 {% endif %}
                 <a href="javascript:;" class="button_action header_dropdown_down">&#9660;</a>
                 <a href="javascript:;" class="button_action header_dropdown_up">&#9650;</a>
-              {% elif request.user and request.user.status == "needs_email_verification" %}
+              {% elif request.user and not request.user.has_privilege('active') %}
               {# the following link should only appear when verification is needed #}
                 <a href="{{ request.urlgen('mediagoblin.user_pages.user_home',
                                  user=request.user.username) }}"
                  "javascript:;"
                {% endif %}
                >{% trans %}log out{% endtrans %}</a>
+              {% elif request.user and request.user.is_banned() %}
+                <a id="logout" href=
+               {% if persona is not defined %}
+                 "{{ request.urlgen('mediagoblin.auth.logout') }}"
+               {% else %}
+                 "javascript:;"
+               {% endif %}
+               >{% trans %}log out{% endtrans %}</a>
               {% endif %}
             {%- elif auth %}
             <a href=
             {%- endif %}
           </div>
           <div class="clear"></div>
-          {% if request.user and request.user.status == 'active' %}
+          {% if request.user and request.user.has_privilege('active') %}
             <div class="header_dropdown">
               <p>
                 <span class="dropdown_title">
index 0951c044029bf0adeaaa3890772d5e0b9421c9d2..b998d1c38fee632379c480e2f6099adf7045d0f2 100644 (file)
@@ -1,3 +1,27 @@
+{#
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors.  See AUTHORS.
+#
+# 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/>.
+#}
+{% extends "mediagoblin/base.html" %}
+
+{% block title %}
+  Terms of Service
+{% endblock %}
+
+{% block mediagoblin_content -%}
 <h2>The gist</h2>
 
 <h2>Terms of Service</h2>
@@ -14,8 +38,8 @@ that may be published from time to time on this Site by Operator (collectively,
 
 Please read this Agreement carefully before accessing or using the Website. By accessing or using any part of the web site, you agree to become bound by the terms and conditions of this agreement. If you do not agree to all the terms and conditions of this agreement, then you may not access the Website or use any services. If these terms and conditions are considered an offer by Operator, acceptance is expressly limited to these terms. The Website is available only to individuals who are at least 13 years old.
 
-<ol>
-  <li>Your {{ app_config['html_title'] }} Account and Site. If you create a
+<ol id="code_of_conduct_list">
+  <li><strong>Your {{ app_config['html_title'] }} Account and Site.</strong> If you create a
     notice stream on the Website, you are responsible for maintaining the
     security of your account and notice stream, and you are fully responsible
     for all activities that occur under the account and any other actions taken
@@ -30,7 +54,7 @@ Please read this Agreement carefully before accessing or using the Website. By a
     including any damages of any kind incurred as a result of such acts or
     omissions.
   </li>
-  <li>Responsibility of Contributors. If you operate a notice stream, comment
+  <li><strong>Responsibility of Contributors.</strong> If you operate a notice stream, comment
     on a notice stream, post material to the Website, post links on the
     Website, or otherwise make (or allow any third party to make) material
     available by means of the Website (any such material, “Content”), You are
@@ -38,7 +62,7 @@ Please read this Agreement carefully before accessing or using the Website. By a
     Content. That is the case regardless of whether the Content in question
     constitutes text, graphics, an audio file, or computer software. By making
     Content available, you represent and warrant that:
-    <ul>
+    <ul class="nested_sublist">
       <li>the downloading, copying and use of the Content will not infringe
         the proprietary rights, including but not limited to the copyright,
         patent, trademark or trade secret rights, of any third party;
@@ -102,7 +126,7 @@ Please read this Agreement carefully before accessing or using the Website. By a
     (ii) terminate or deny access to and use of the Website to any individual
     or entity for any reason, in Operator’s sole discretion.
   </li>
-  <li>Responsibility of Website Visitors. Operator has not reviewed, and cannot
+  <li><strong>Responsibility of Website Visitors.</strong> Operator has not reviewed, and cannot
     review, all of the material, including computer software, posted to the
     Website, and cannot therefore be responsible for that material’s content,
     use or effects. By operating the Website, Operator does not represent or
@@ -121,7 +145,7 @@ Please read this Agreement carefully before accessing or using the Website. By a
     visitors of the Website, or from any downloading by those visitors of
     content there posted.
   </li>
-  <li>Content Posted on Other Websites. We have not reviewed, and cannot
+  <li><strong>Content Posted on Other Websites.</strong> We have not reviewed, and cannot
     review, all of the material, including computer software, made available
     through the websites and webpages to which {{ app_config['html_title'] }}
     links, and that link to {{ app_config['html_title'] }}. Operator does not
@@ -134,7 +158,7 @@ Please read this Agreement carefully before accessing or using the Website. By a
     disclaims any responsibility for any harm resulting from your use of
     external websites and webpages.
   </li>
-  <li>Copyright Infringement and DMCA Policy. As Operator asks others to
+  <li><strong>Copyright Infringement and DMCA Policy.</strong> As Operator asks others to
     respect its intellectual property rights, it respects the intellectual
     property rights of others. If you believe that material located on or
     linked to by {{ app_config['html_title'] }} violates your copyright, you
@@ -148,7 +172,7 @@ Please read this Agreement carefully before accessing or using the Website. By a
     the Website. In the case of such termination, Operator will have no
     obligation to provide a refund of any amounts previously paid to Operator.
   </li>
-  <li>Intellectual Property. This Agreement does not transfer from Operator to
+  <li><strong>Intellectual Property.</strong> This Agreement does not transfer from Operator to
     you any Operator or third party intellectual property, and all right,
     title and interest in and to such property will remain (as between the
     parties) solely with Operator. {{ app_config['html_title'] }}, the
@@ -161,7 +185,7 @@ Please read this Agreement carefully before accessing or using the Website. By a
     Website grants you no right or license to reproduce or otherwise use any
     Operator or third-party trademarks.
   </li>
-  <li>Changes. Operator reserves the right, at its sole discretion, to modify
+  <li><strong>Changes.</strong> Operator reserves the right, at its sole discretion, to modify
     or replace any part of this Agreement. It is your responsibility to check
     this Agreement periodically for changes. Your continued use of or access
     to the Website following the posting of any changes to this Agreement
@@ -170,7 +194,7 @@ Please read this Agreement carefully before accessing or using the Website. By a
     release of new tools and resources). Such new features and/or services
     shall be subject to the terms and conditions of this Agreement.
   </li>
-  <li>Termination. Operator may terminate your access to all or any part of
+  <li><strong>Termination.</strong> Operator may terminate your access to all or any part of
     the Website at any time, with or without cause, with or without notice,
     effective immediately. If you wish to terminate this Agreement or your
     {{ app_config['html_title'] }} account (if you have one), you may simply
@@ -179,7 +203,7 @@ Please read this Agreement carefully before accessing or using the Website. By a
     including, without limitation, ownership provisions, warranty disclaimers,
     indemnity and limitations of liability.
   </li>
-  <li>Disclaimer of Warranties. The Website is provided “as is”. Operator and
+  <li><strong>Disclaimer of Warranties.</strong> The Website is provided “as is”. Operator and
     its suppliers and licensors hereby disclaim all warranties of any kind,
     express or implied, including, without limitation, the warranties of
     merchantability, fitness for a particular purpose and non-infringement.
@@ -189,7 +213,7 @@ Please read this Agreement carefully before accessing or using the Website. By a
     understand that you download from, or otherwise obtain content or services
     through, the Website at your own discretion and risk.
   </li>
-  <li>Limitation of Liability. In no event will Operator, or its suppliers or
+  <li><strong>Limitation of Liability.</strong> In no event will Operator, or its suppliers or
     licensors, be liable with respect to any subject matter of this agreement
     under any contract, negligence, strict liability or other legal or
     equitable theory for: (i) any special, incidental or consequential damages;
@@ -201,7 +225,7 @@ Please read this Agreement carefully before accessing or using the Website. By a
     reasonable control. The foregoing shall not apply to the extent prohibited
     by applicable law.
   </li>
-  <li>General Representation and Warranty. You represent and warrant that (i)
+  <li><strong>General Representation and Warranty.</strong> You represent and warrant that (i)
     your use of the Website will be in strict accordance with the Operator
     Privacy Policy, with this Agreement and with all applicable laws and
     regulations (including without limitation any local laws or regulations in
@@ -212,13 +236,13 @@ Please read this Agreement carefully before accessing or using the Website. By a
     infringe or misappropriate the intellectual property rights of any third
     party.
   </li>
-  <li>Indemnification. You agree to indemnify and hold harmless Operator, its
+  <li><strong>Indemnification.</strong> You agree to indemnify and hold harmless Operator, its
     contractors, and its licensors, and their respective directors, officers,
     employees and agents from and against any and all claims and expenses,
     including attorneys’ fees, arising out of your use of the Website,
     including but not limited to out of your violation this Agreement.
   </li>
-  <li>Miscellaneous. This Agreement constitutes the entire agreement between
+  <li><strong>Miscellaneous.</strong> This Agreement constitutes the entire agreement between
     Operator and you concerning the subject matter hereof, and they may only
     be modified by a written amendment signed by an authorized executive of
     Operator, or by the posting by Operator of a revised version. If any part
@@ -241,3 +265,5 @@ ShareAlike 3.0 License. Modifications to remove reference to "VIP services",
 rename "blog" to "notice stream", remove the choice-of-venue clause, and add
 variables specific to instances of this software made by Control Yourself, Inc.
 and made available under the terms of the same license.
+
+{% endblock -%}
index 1be9dd8053579b2c9ae4e5654b90a339322d9e13..17a0860394d9266be283ed58d5cdc85673fb2a85 100644 (file)
@@ -37,7 +37,7 @@
   {% if not user %}
     <p>{% trans %}Sorry, no such user found.{% endtrans %}</p>
   {# User exists, but needs verification #}
-  {% elif user.status == "needs_email_verification" %}
+  {% elif not user.has_privilege('active') %}
     <div class="form_box">
     <h1>{% trans %}Email verification needed{% endtrans %}</h1>
     <p>
index 8ac0b9888d7ac1fc9d6359af6d78cda887ca60b1..4b449c760a54e2bc30c58a4564bff8f9596a793d 100644 (file)
@@ -34,7 +34,7 @@
   </h1>
 
   {% if request.user %}
-    {% if request.user.status == 'active' %}
+    {% if request.user.has_privilege('active') %}
       <p>
         <a href="{{ request.urlgen('mediagoblin.submit.collection',
                                             user=user.username) }}">
index de92fb5e7f8f469fc5f9857c4584e94eab02107b..d4ce764ff41c6199249b391e126f879f11972d80 100644 (file)
@@ -43,7 +43,7 @@
     <p>{% trans %}Sorry, no such user found.{% endtrans %}</p>
 
   {# User exists, but needs verification #}
-  {% elif user.status == "needs_email_verification" %}
+  {% elif not user.status.has_privilege('active') %}
     {% if user == request.user %}
       {# this should only be visible when you are this user #}
       <div class="form_box">
index edbd27ee77d15f3d46d457e6f6407e54f512b219..63c126820a3406d97f29f2fff103215b9cbf12be 100644 (file)
@@ -96,8 +96,6 @@ def test_register_views(test_app):
     new_user = mg_globals.database.User.query.filter_by(
         username=u'angrygirl').first()
     assert new_user
-    assert new_user.status == u'needs_email_verification'
-    assert new_user.email_verified == False
 
     ## Make sure that the proper privileges are granted on registration
 
@@ -137,8 +135,6 @@ def test_register_views(test_app):
     new_user = mg_globals.database.User.query.filter_by(
         username=u'angrygirl').first()
     assert new_user
-    assert new_user.status == u'needs_email_verification'
-    assert new_user.email_verified == False
 
     ## Verify the email activation works
     template.clear_test_template_context()
@@ -151,8 +147,6 @@ def test_register_views(test_app):
     new_user = mg_globals.database.User.query.filter_by(
         username=u'angrygirl').first()
     assert new_user
-    assert new_user.status == u'active'
-    assert new_user.email_verified == True
 
     # Uniqueness checks
     # -----------------
index 919877c9e76d2b39c449bb5ea3d90f4b94faee27..3e9bf22fa338cb73c8936a60ab9233b7e65a38c6 100644 (file)
@@ -112,8 +112,6 @@ class TestPersonaPlugin(object):
             # Get user and detach from session
             test_user = mg_globals.database.User.query.filter_by(
                 username=u'chris').first()
-            test_user.email_verified = True
-            test_user.status = u'active'
             test_user.save()
             test_user = mg_globals.database.User.query.filter_by(
                 username=u'chris').first()
index 931b740cf60e96d70f971c6783965d5318d48fc9..4f55588496edc55f3d66bd8be114206fcf509011 100644 (file)
@@ -57,7 +57,7 @@ def user_home(request, page):
     user = User.query.filter_by(username=request.matchdict['user']).first()
     if not user:
         return render_404(request)
-    elif user.status != u'active':
+    elif not user.has_privilege(u'active'):
         return render_to_response(
             request,
             'mediagoblin/user_pages/user.html',
@@ -474,9 +474,8 @@ def atom_feed(request):
     generates the atom feed with the newest images
     """
     user = User.query.filter_by(
-        username = request.matchdict['user'],
-        status = u'active').first()
-    if not user:
+        username = request.matchdict['user']).first()
+    if not user or not user.has_privilege(u'active'):
         return render_404(request)
 
     cursor = MediaEntry.query.filter_by(
@@ -537,9 +536,8 @@ def collection_atom_feed(request):
     generates the atom feed with the newest images from a collection
     """
     user = User.query.filter_by(
-        username = request.matchdict['user'],
-        status = u'active').first()
-    if not user:
+        username = request.matchdict['user']).first()
+    if not user or not user.has_privilege(u'active'):
         return render_404(request)
 
     collection = Collection.query.filter_by(