[copr] master: Allow deleting coprs (010246d)

bkabrda at fedoraproject.org bkabrda at fedoraproject.org
Wed Mar 27 13:46:52 UTC 2013


Repository : http://git.fedorahosted.org/cgit/copr.git

On branch  : master

>---------------------------------------------------------------

commit 010246d4e7351c9113cf1c3b4cee7aa20ae26af5
Author: Bohuslav Kabrda <bkabrda at redhat.com>
Date:   Wed Mar 27 14:46:33 2013 +0100

    Allow deleting coprs


>---------------------------------------------------------------

 coprs_frontend/coprs/forms.py                      |    3 +
 coprs_frontend/coprs/logic/coprs_logic.py          |   17 ++++++++
 .../coprs/templates/coprs/_coprs_forms.html        |   17 ++++++++
 coprs_frontend/coprs/templates/coprs/detail.html   |    5 ++
 .../coprs/templates/coprs/detail/delete.html       |   14 +++++++
 .../coprs/views/coprs_ns/coprs_general.py          |   24 +++++++++++
 coprs_frontend/coprs/whoosheers.py                 |    4 ++
 .../tests/test_views/test_coprs_ns/test_general.py |   41 ++++++++++++++++++++
 8 files changed, 125 insertions(+), 0 deletions(-)

diff --git a/coprs_frontend/coprs/forms.py b/coprs_frontend/coprs/forms.py
index 5c80c33..7c7cf35 100644
--- a/coprs_frontend/coprs/forms.py
+++ b/coprs_frontend/coprs/forms.py
@@ -123,6 +123,9 @@ class CoprFormFactory(object):
 
         return F
 
+class CoprDeleteForm(wtf.Form):
+    verify = wtf.TextField('Confirm deleting by typing "yes"',
+                           validators=[wtf.Required(), wtf.Regexp(r'^yes$', message='Type "yes" - without the quotes, lowercase.')])
 
 class BuildForm(wtf.Form):
     pkgs = wtf.TextAreaField('Pkgs',
diff --git a/coprs_frontend/coprs/logic/coprs_logic.py b/coprs_frontend/coprs/logic/coprs_logic.py
index 29aa6b0..1a83147 100644
--- a/coprs_frontend/coprs/logic/coprs_logic.py
+++ b/coprs_frontend/coprs/logic/coprs_logic.py
@@ -112,6 +112,23 @@ class CoprsLogic(object):
         db.session.add(copr)
 
     @classmethod
+    def delete(cls, user, copr, check_for_duplicates=True):
+        # for the time being, we authorize user to do this in view...
+        # TODO: do we want to dump the information somewhere, so that we can search it in future?
+        cls.raise_if_unfinished_action(user, copr)
+        action = models.Action(action_type=helpers.ActionTypeEnum('delete'),
+                               object_type='copr',
+                               object_id=copr.id,
+                               old_value='{0}/{1}'.format(copr.owner.name, copr.name),
+                               new_value='',
+                               created_on=int(time.time()))
+
+        db.session.add(action)
+        db.session.delete(copr)
+
+        return copr
+
+    @classmethod
     def exists_for_user(cls, user, coprname):
         existing = models.Copr.query.filter(models.Copr.name==coprname).\
                                      filter(models.Copr.owner_id==user.id)
diff --git a/coprs_frontend/coprs/templates/coprs/_coprs_forms.html b/coprs_frontend/coprs/templates/coprs/_coprs_forms.html
index b3f6742..a0f55e3 100644
--- a/coprs_frontend/coprs/templates/coprs/_coprs_forms.html
+++ b/coprs_frontend/coprs/templates/coprs/_coprs_forms.html
@@ -31,6 +31,23 @@
   </form>
 {% endmacro %}
 
+{% macro copr_delete_form(form, copr) %}
+  <form action="{{ url_for('coprs_ns.copr_delete', username=copr.owner.name, coprname=copr.name) }}" method="post">
+    <dl>
+      {{ form.csrf_token }}
+      <dd>
+        {% if form.verify.errors %}
+          {% for error in form.verify.errors %}
+            <p class="form-error">{{ error }}</p>
+          {% endfor %}
+        {% endif %}
+      </dd>
+      {{ form.verify }}
+      <dt><input type="submit" value="Delete"></dt>
+    </dl>
+  </form>
+{% endmacro %}
+
 {% macro copr_permissions_form(form, copr, permissions) %}
   {% if permissions %}
     <form action="{{ url_for('coprs_ns.copr_update_permissions', username=copr.owner.name, coprname=copr.name) }}" method=post>
diff --git a/coprs_frontend/coprs/templates/coprs/detail.html b/coprs_frontend/coprs/templates/coprs/detail.html
index ef0f097..749ffb6 100644
--- a/coprs_frontend/coprs/templates/coprs/detail.html
+++ b/coprs_frontend/coprs/templates/coprs/detail.html
@@ -27,6 +27,11 @@
           <a href="{{ url_for('coprs_ns.copr_edit', username = copr.owner.name, coprname = copr.name) }}">Edit</a>
         </li>
       {% endif %}
+      {% if g.user and g.user == copr.owner %}
+        <li class="{% block delete_selected %}unselected{% endblock %}">
+          <a href="{{ url_for('coprs_ns.copr_delete', username=copr.owner.name, coprname=copr.name) }}">Delete</a>
+        </li>
+      {% endif %}
     </ul>
   </div>
   {% block detail_body %}{% endblock %}
diff --git a/coprs_frontend/coprs/templates/coprs/detail/delete.html b/coprs_frontend/coprs/templates/coprs/detail/delete.html
new file mode 100644
index 0000000..0e65de0
--- /dev/null
+++ b/coprs_frontend/coprs/templates/coprs/detail/delete.html
@@ -0,0 +1,14 @@
+{% extends "coprs/detail.html" %}
+{% block title %}Delete {{ copr.owner.name }}/{{ copr.name }}?{% endblock %}
+{% block delete_selected %}selected{% endblock %}
+{% from "coprs/_coprs_forms.html" import copr_delete_form %}
+
+{% block detail_body %}
+  <p>If you really want to delete this Copr, you'll have to answer this riddle:</p>
+  <p>{{ range(5)|random }}.{{ range(10)|random }} hens lay {{ range(5)|random }}.{{ range(10)|random }} eggs in
+  {{ range(5)|random }}.{{ range(10)|random }} days. How many eggs do {{ range(5)|random }}.{{ range(10)|random }}
+  hens lay in {{ range(5)|random }}.{{ range(10)|random }} days?</p>
+  <p>Ok, kidding, just type "<strong>yes</strong>" into the below box.</p>
+  {{ copr_delete_form(form, copr) }}
+
+{% endblock %}
diff --git a/coprs_frontend/coprs/views/coprs_ns/coprs_general.py b/coprs_frontend/coprs/views/coprs_ns/coprs_general.py
index fc1a0ad..6da142e 100644
--- a/coprs_frontend/coprs/views/coprs_ns/coprs_general.py
+++ b/coprs_frontend/coprs/views/coprs_ns/coprs_general.py
@@ -236,3 +236,27 @@ def copr_update_permissions(username, coprname):
         flask.flash('Copr permissions were updated successfully.')
 
     return flask.redirect(flask.url_for('coprs_ns.copr_detail', username = copr.owner.name, coprname = copr.name))
+
+ at coprs_ns.route('/detail/<username>/<coprname>/delete/', methods=['GET', 'POST'])
+ at login_required
+def copr_delete(username, coprname):
+    form = forms.CoprDeleteForm()
+    copr = coprs_logic.CoprsLogic.get(flask.g.user, username, coprname).first()
+    # only owner can delete a copr
+    if flask.g.user != copr.owner:
+        flask.flash('Only owners may delete their Coprs.')
+        return flask.redirect(flask.url_for('coprs_ns.copr_detail', username=username, coprname=coprname))
+
+    if form.validate_on_submit():
+        try:
+            coprs_logic.CoprsLogic.delete(flask.g.user, copr)
+        except exceptions.ActionInProgressException as e:
+            db.session.rollback()
+            flask.flash('Can\'t manipulate this Copr, there is another operation in progress: {0}'.format(e.action))
+            return flask.redirect(flask.url_for('coprs_ns.copr_detail', username=username, coprname=coprname))
+        else:
+            db.session.commit()
+            flask.flash('Copr was deleted successfully.')
+            return flask.redirect(flask.url_for('coprs_ns.coprs_by_owner', username=username))
+    else:
+        return flask.render_template('coprs/detail/delete.html', form=form, copr=copr)
diff --git a/coprs_frontend/coprs/whoosheers.py b/coprs_frontend/coprs/whoosheers.py
index 45b5ab6..cefae0f 100644
--- a/coprs_frontend/coprs/whoosheers.py
+++ b/coprs_frontend/coprs/whoosheers.py
@@ -53,3 +53,7 @@ class CoprUserWhoosheer(AbstractWhoosheer):
                             coprname=copr.name,
                             description=copr.description,
                             instructions=copr.instructions)
+
+    @classmethod
+    def delete_copr(cls, writer, copr):
+        writer.delete_by_term('copr_id', copr.id)
diff --git a/coprs_frontend/tests/test_views/test_coprs_ns/test_general.py b/coprs_frontend/tests/test_views/test_coprs_ns/test_general.py
index 691276f..63f3a06 100644
--- a/coprs_frontend/tests/test_views/test_coprs_ns/test_general.py
+++ b/coprs_frontend/tests/test_views/test_coprs_ns/test_general.py
@@ -370,3 +370,44 @@ class TestCoprUpdatePermissions(CoprsTestCase):
                        data = {'copr_builder_1': '2', 'copr_admin_3': '2'},
                        follow_redirects = True)
             assert 'Copr permissions were updated' in r.data
+
+class TestCoprDelete(CoprsTestCase):
+    def test_delete(self, f_users, f_coprs, f_db):
+        with self.tc as c:
+            with c.session_transaction() as s:
+                s['openid'] = self.u1.openid_name
+
+            self.db.session.add_all([self.u1, self.c1])
+            r = c.post('/coprs/detail/{0}/{1}/delete/'.format(self.u1.name, self.c1.name),
+                       data = {'verify': 'yes'},
+                       follow_redirects = True)
+            assert 'Copr was deleted successfully' in r.data
+            assert self.models.Action.query.first().id == self.c1.id
+            assert not self.models.Copr.query.filter(self.models.Copr.id==self.c1.id).first()
+
+    def test_copr_delete_does_not_delete_if_verify_filled_wrongly(self, f_users, f_coprs, f_db):
+        with self.tc as c:
+            with c.session_transaction() as s:
+                s['openid'] = self.u1.openid_name
+
+            self.db.session.add_all([self.u1, self.c1])
+            r = c.post('/coprs/detail/{0}/{1}/delete/'.format(self.u1.name, self.c1.name),
+                       data = {'verify': 'no'},
+                       follow_redirects = True)
+            assert 'Copr was deleted successfully' not in r.data
+            assert not self.models.Action.query.first()
+            assert self.models.Copr.query.filter(self.models.Copr.id==self.c1.id).first()
+
+    def test_non_owner_cant_delete(self, f_users, f_coprs, f_db):
+        with self.tc as c:
+            with c.session_transaction() as s:
+                s['openid'] = self.u2.openid_name
+
+            self.db.session.add_all([self.u1, self.u2, self.c1])
+            r = c.post('/coprs/detail/{0}/{1}/delete/'.format(self.u1.name, self.c1.name),
+                       data = {'verify': 'yes'},
+                       follow_redirects = True)
+            self.db.session.add_all([self.c1])
+            assert 'Copr was deleted successfully' not in r.data
+            assert not self.models.Action.query.first()
+            assert self.models.Copr.query.filter(self.models.Copr.id==self.c1.id).first()



More information about the copr-devel mailing list