1. Jon Molesa
  2. qastack

Commits

Julio Flores-Schwarzbeck  committed 148ce6b

Implementing editing questions (by the question creator
or by the SysAdmin) - Certain conditions apply.
NOTE: Do not use this version in "production", it still has
several bugs such as the incorrect update of the tag count
in the "tags" page and (possibly) other untested areas,
I'll run a violent debugging session soon and commit again.

  • Participants
  • Parent commits 4bcb84a
  • Branches default

Comments (0)

Files changed (4)

File controllers/members.py

View file
  • Ignore whitespace
         message=parse_content(message),
         creation_date=request.now,
         read_flag=False)
-    redirect(redirect_url)
+    redirect(redirect_url)
+    
+    
+@auth_user.requires_login()
+def edit_question():
+    """ Questions Can be edited:
+    - By the creator of the question
+    - By the SysAdmin
+    Questions may not be edited:
+    - If the question has already be answered
+    - Except by the SysAdmin
+    
+    """
+    
+    req = request.vars
+    view_info = {'errors': []}
+    auth_user_id = auth_user.get_user_id()
+    if req.form_submitted:
+        qid = req.qid
+        # Save Form information
+        if req.update_question:
+            # Information needed at this point:
+            title = req.question_title.strip()
+            content = req.question.strip()
+            tags = req.tags.lower().strip()
+            if title and content and tags:
+                # All seems to be fine at this point...
+                # Update this question
+                db(db.questions.id==qid).update(title=title,
+                                                description=content,
+                                                modified_by=auth_user_id,
+                                                modified_on=request.now)
+                # Update the tags for this question (remove/re_add)
+                # This is a little tricky, since if a tag is removed, we
+                # also need to remove or decrease the tag count from
+                # out master tag table,
+                
+                # Grab the current tag ids that this question has (before
+                # any updates)
+                sql_tags = db((db.tags.is_enabled==True) &\
+                    (db.question_tags.question_id==qid) &\
+                    (db.question_tags.tag_id==db.tags.id)).select(
+                    db.tags.id)
+                current_tag_ids = [tag.id for tag in sql_tags]
+                
+                # wipe out all the tags for this question
+                db(db.question_tags.question_id==qid).delete()
+                new_tag_ids = []
+                for tag in tags.split(','):
+                    # if this tag does not exist in the master tags table,
+                    # add it, along with a reference to the ID into our
+                    # question_tags table
+                    is_tag = db(db.tags.tagname==tag).select(db.tags.id)
+                    if is_tag:
+                        # Tag exists already, use its id to add the new
+                        # tag pertaining this question
+                        tag_id = is_tag[0].id
+                    else:
+                        # No master tag exists, create it
+                        tag_id = db.tags.insert(tagname=tag,
+                                                is_enabled=True,
+                                                tag_cnt=1)
+                    # Finally, add this tag_id to our question_tags table
+                    db.question_tags.insert(question_id=qid,
+                                            tag_id=tag_id)
+                    new_tag_ids.append(tag_id)
+                    
+                # Here we need to do a bit of clean-up on the master tags,
+                # if the user removed any of the existing tags in the question,
+                # I need to decrement the tag_cnt value of the master tags
+                # table, however, if the tag_cnt value reaches 0, then I need
+                # to actually delete the tag record itself...
+                # for this, I am relying on my current_tag_ids/new_tag_ids
+                # variables..
+                # The elements in current_tag_ids that are NOT in new_tag_ids
+                # will have to be subtracted or deleted from table tags
+                old_set = set(current_tag_ids)
+                new_set = set(new_tag_ids)
+                remove_tag_list = list(old_set.difference(new_set))
+                for tag_id in remove_tag_list:
+                    cur_tag_cnt = db(db.tags.id==tag_id).select(
+                        db.tags.tag_cnt)[0].tag_cnt
+                    if cur_tag_cnt - 1 == 0:
+                        # Remove it from master tag list
+                        db(db.tags.id==tag_id).delete()
+                    else:
+                        # Update the tag_cnt only, don't delete it
+                        db(db.tags.id==tag_id).update(tag_cnt=cur_tag_cnt-1)
+                redirect(URL(r=request, c='default', f='view', args=[qid]))
+            else:
+                wiew_info['errors'].append("Please make sure you specify "
+                                           "Title, Question Content and "
+                                           "at least one tag to continue.")
+        else:
+            redirect(URL(r=request, c='default', f='view', args=[qid]))
+    else:
+        qid = request.args[0]
+    # Grab the question
+    question = db(db.questions.id==qid).select(db.questions.ALL)[0]
+    # .. also get the tags
+    sql_tags = db((db.tags.is_enabled==True) &\
+        (db.question_tags.question_id==qid) &\
+        (db.question_tags.tag_id==db.tags.id)).select(db.tags.tagname)
+    tags = ','.join([tag.tagname for tag in sql_tags])
+    # Set the can_edit flag here instead of in the view...
+    can_edit = False
+    if auth_user.is_admin():
+        can_edit = True
+    else:
+        # No admin, can you still edit?
+        if question.created_by == auth_user_id and\
+                                question.is_visible and\
+                                not (question.is_answered or\
+                                     question.is_closed):
+            can_edit = True
+    return dict(question=question,
+                view_info=view_info,
+                tags=tags,
+                can_edit=can_edit)

File models/db.py

View file
  • Ignore whitespace
 # -*- coding: utf-8 -*-
 
 # Control Migrations "automatically"
-migrate = True
+migrate = False
 
 # Allow auto completion work on Wing IDE
-if 0:
-    import db
+if 0: 
+    from gluon.globals import * 
+    from gluon.html import * 
+    from gluon.http import * 
+    from gluon.sqlhtml import SQLFORM, SQLTABLE, form_factory 
+    session = Session() 
+    request = Request() 
+    response = Response()
 
 db = DAL('sqlite://qastack.sqlite')
 #db = DAL('mysql://web2py:py2web@ds9.virtual:3306/qastack')

File views/default/view.html

View file
  • Ignore whitespace
                                 args=[question.questions.id])}}"
                                 title="{{=XML(T('Comment on this Question'))}}"
                                 class="bold">{{=XML(T('Comment on this Question'))}}</a>
+                            <!-- if the user has permissions to edit questions
+                            (being an admin, etc, or the logged in user is the
+                            creator of this question, then he can edit this) //-->
+                            | <a href="{{=URL(r=request, c='members', f='edit_question', args=[question.questions.id])}}" title="" class="bold"
+                            title="{{=XML(T('Edit Question'))}}">{{=XML(T('Edit Question'))}}</a> 
                         </div>
                     {{pass}}
                 </td>

File views/members/edit_question.html

View file
  • Ignore whitespace
+{{extend 'qastack_layout.html'}}
+
+<h2 class="fancy">{{=XML(T('Edit Question'))}}</h2>
+
+{{if view_info['errors']:}}
+    <p class="err">{{=XML(T('There was one or more messages generated while processing your request, please review the following'))}}</p>
+    <ul>
+        {{for error in view_info['errors']:}}
+            <li class="err">{{=XML(T(error))}}</li>
+        {{pass}}
+    </ul>
+{{pass}}
+
+{{if can_edit:}}
+    <form id="edit_form" method="post" action="">
+        <fieldset id="ask_form_fields">
+            <input type="hidden" id="form_submitted" name="form_submitted" value="1" />
+            <input type="hidden" id="qid" name="qid" value="{{=question.id}}" />
+            <table cellspacing="1" cellpadding="1" style="width:100%;">
+                <tbody>
+                    <tr>
+                        <td style="width:20%;">{{=XML(T('Question Title'))}}</td>
+                        <td style="width:80%;">
+                            <input type="text" id="question_title"
+                            name="question_title"
+                            value="{{=request.vars.get('question_title', question.title)}}"
+                                   style="width:80%;" />
+                        </td>
+                    </tr>
+                    <tr>
+                        <td>{{=XML(T('Question'))}}:</td>
+                        <td>
+                            <textarea id="question" name="question"
+                            cols="0" rows="0"
+                            style="width:80%;height:250px;">{{=request.vars.get('question', question.description)}}</textarea>
+                        </td>
+                    </tr>
+                    <tr>
+                        <td>{{=XML(T('Tags'))}}:</td>
+                        <td>
+                            <input type="text" id="tags" name="tags" value="{{=request.vars.get('tags', tags)}}"
+                                   style="width:60%;" />
+                            <a href="javascript:void(0);" title="" onclick="return false;"
+                            class="help"><img src="{{=URL(r=request, c='static/images', f='questionmark.png')}}" alt=""
+                            style="vertical-align:middle;height:20px;width:20px;border:0;" /><div>Place as many tags as you think
+                            they are relevant to this question, please separate each tag by a comma.</div></a>
+                        </td>
+                    </tr>
+                </tbody>
+            </table>
+        </fieldset>
+        
+        <div class="paragraph-all">
+            <input type="submit" id="update_question" name="update_question" value="{{=XML(T('Update Question'))}}"
+                   onclick="return confirm('Please confirm you wish to edit this question.');" />
+            <input type="submit" id="cancel_edit" name="cancel_edit" value="{{=XML(T('Cancel'))}}" />
+        </div>
+    
+        <div class="paragraph">
+            Basic html is allowed, use of <span class="explain">&lt;b&gt; &lt;i&gt;</span> ok to use, in addition, use the following <i>pseudo-code</i>
+            to highlight and nicely format your code if you post any code snippet <i>(Click to Insert)</i>:
+            <a href="javascript:void(0);" onclick="add_helper('[code-python][/code-python]');return false;" title="">[code-python]</a>,
+            <a href="javascript:void(0);" onclick="add_helper('[code-c][/code-c]');return false;" title="">[code-c]</a>,
+            <a href="javascript:void(0);" onclick="add_helper('[code-c++][/code-c++]');return false;" title="">[code-c++]</a>,
+            <a href="javascript:void(0);" onclick="add_helper('[code-c#][/code-c#]');return false;" title="">[code-c#]</a>,
+            <a href="javascript:void(0);" onclick="add_helper('[code-php][/code-php]');return false;" title="">[code-php]</a>,
+            <a href="javascript:void(0);" onclick="add_helper('[code-java][/code-java]');return false;" title="">[code-java]</a>,
+            or
+            <a href="javascript:void(0);" onclick="add_helper('[code][/code]');return false;" title="">[code]</a>
+            (for a language not included in the previous code definitions).<br />Close your code snippet
+            with a matching <span class="explain">[/code-<i>language</i>]</span> if applicable or manually added.
+        </div>
+    
+    </form>
+    
+    <script type="text/javascript">
+    <!--
+        function add_helper(s_value) {
+            var oquestion = document.getElementById('question');
+    
+            // IE support
+            if (document.selection) {
+                oquestion.focus();
+                sel = document.selection.createRange();
+                sel.text = s_value;
+            }
+            // MOZILLA/NETSCAPE support
+            else if (oquestion.selectionStart || oquestion.selectionStart == 0) {
+                var start_pos = oquestion.selectionStart;
+                var end_pos = oquestion.selectionEnd;
+                oquestion.value = oquestion.value.substring(0, start_pos) + s_value + oquestion.value.substring(end_pos, oquestion.value.length);
+            } else {
+                oquestion.value += s_value;
+            }    
+        }
+        // Put the focus on the comment textarea
+        document.getElementById('question_title').focus();
+    //-->
+    </script>
+{{else:}}
+    <p class="error">Unable to edit question, this may be due to the following reasons:</p>
+    <ul>
+        <li class="error">You are not authorized to edit this question.</li>
+        <li class="error">This question has been closed, disabled by the System Administrator.</li>
+        <li class="error">This question has an answer that has been marked as &quot;accepted&quot;</li>
+    </ul>
+    <p><a href="javascript:void(0);" title="" onclick="history.go(-1);">Go Back</a></p>
+{{pass}}