Commits

Javier Novoa C. committed 6b35535

Improving interface

-Validations ready
-Improvements at admin interface
-Improvements at general UI interface
-Added representative image at the top of documents
-Added logout function for admin interface
-Docman requires admin authentication

  • Participants
  • Parent commits cbd235f

Comments (0)

Files changed (10)

+.*\~
 .*\.pyc
 comment_compile_area/
 fixtures/

File conf/settings.py

 from django.conf import settings as DJANGO_SETTINGS
 from os import getcwd, sep
 from tempfile import mkdtemp
+STATIC_URL = DJANGO_SETTINGS.STATIC_URL
 MEDIA_URL = DJANGO_SETTINGS.MEDIA_URL
 MEDIA_ROOT = DJANGO_SETTINGS.MEDIA_ROOT
 EMAIL_FROM = DJANGO_SETTINGS.EMAIL_FROM
 To REJECT the comment, click here: {{comment.rejection_code}}
 '''
 
+# Header image
+header_image = STATIC_URL
+
+# Admin link
+admin_link = ("/" if url_views_prefix != "" else "") + url_views_prefix + "/_admin"
+
 # Create a ``local_settings.py`` file that overrides settings in this file.
 # This is useful if you update ucommentapp from revision control and don't want
 # to loose your settings everytime.  Be sure to check for diffs against
 from markitup.widgets import MarkItUpWidget
 from django import forms
 
+import os
+from django.template.defaultfilters import slugify
+from docutils.core import publish_parts
+
 # Docman form
 class DocManForm(forms.Form):
-    title = forms.CharField(label="Titulo")
-    text = forms.CharField(label="Texto", widget=MarkItUpWidget())
+    title = forms.CharField(label="Title")
+    text = forms.CharField(label="Text", widget=MarkItUpWidget())
+
+    def clean_title(self):
+        title = self.cleaned_data['title']
+        # Sanitize title
+        self.sanitized_title = str(slugify(title))
+        self.added_fname = self.sanitized_title+".rst"
+
+        # Verify that file doesn't exists already
+        if os.path.exists(self.fname_dir + self.added_fname):
+            raise forms.ValidationError("File already exists! Maybe you should change the Title?")
+
+        return title
+
+    def clean_text(self):
+        text = self.cleaned_data['text']
+        # Validate document (there are no RST errors)
+        parts = publish_parts(source=text, writer_name="html")
+        if parts['fragment'].find("ERROR") is not -1:
+            raise forms.ValidationError("Text is not valid reStructuredText format!\n %s" % parts['fragment'])
+
+        return text

File templates/admin.html

+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+  <meta http-equiv="Content-type" content="text/html; charset=utf-8">
+  <title>{{ html_title }}</title>
+  <style type="text/css" media="all"><!--  @import url({{ stylesheet_link }}); --></style>
+</head>
+
+<body id="ucomment-html-body" class="{{css_body_class}}">
+  <a href="{{ root }}">
+    <img src="{{ header_img }}" /></a>
+  <ul>
+    <li><a href="{{ root }}">Table of Contents for your document</a></li>
+    <li><a href="{{ admidx }}">The Django admin page for your site</a></li>
+    <li><a href="{{ pubupd }}">Publish or update the document</a></li>
+    <li><a href="{{ docman }}">Add document</a></li>
+    <li>Backup your application by <a href="{{ dump }}">dumping objects to fixtures</a></li>
+  </ul>
+  <a href="{{ logout }}">Logout</a>
+</body>
+</html>

File templates/admin_signin.html

+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+  <meta http-equiv="Content-type" content="text/html; charset=utf-8">
+  <title>{{ html_title }}</title>
+  <style type="text/css" media="all"><!--  @import url({{ stylesheet_link }}); --></style>
+</head>
+
+<body id="ucomment-html-body" class="{{css_body_class}}">
+  <a href="{{ root }}">
+    <img src="{{ header_img }}" /></a>
+  <br />
+  <a href="{{ root }}">Table of Contents for your document</a>
+  <p>Please sign-in first with your Django (admin) credentials:
+    <form action="{{ request.path }}" method="POST">{{ csrf_token }}
+      <label for="username">Username:</label>
+      <input type="text" name="username" /><br />
+      <label for="password">Password:</label>
+      <input type="password" name="password" /><br />
+      <input type="submit" value="Log in">
+    </form>
+  </p>
+</body>
+</html>

File templates/docman/docmanpage_form.html

-<html>
-<head>
-  {{ form.media }}
-</head>
-<body>
-  {% if form.errors %}
-    <p class="errors">
-      Error en los datos! Por favor corrígelos...
-    </p>
-  {% endif %}
-
-  <form action="" method="post">
-    <table>
-      {{ form.as_table }}
-    </table>
-    <input type="submit" value="Enviar" />
-  </form>
-</body>
-</html>

File templates/docmanpage_form.html

+<html>
+<head>
+  {{ form.media }}
+</head>
+<body>
+  {% if messages %}
+  <ul>
+    {% for message in messages %}
+    <li>{{ message }}</li>
+    {% endfor %}
+  </ul>
+  {% endif %}
+
+  {% if form.errors %}
+    <p class="errors">
+      Data error, please correct...
+    </p>
+  {% endif %}
+
+  <form action="" method="post">
+    <table>
+      {{ form.as_table }}
+    </table>
+    <input type="submit" value="Enviar" />
+  </form>
+</body>
+</html>

File templates/document-page.html

 
 	<style type="text/css" media="all"><!--  @import url({{stylesheet_link}}); --></style>
 
-	<div id="ucomment-header"><h1>
-		<a href="{{ root_link.link }}" title="{{ root_link.title|safe }}">{{ root_link.title|safe }}</a></h1>
+	<a href="{{ root_link.link }}"><img src="{{ header_img }}" alt="{{ root_link.title|safe }}" title="{{ root_link.title|safe }}" /></a>
+	<div id="ucomment-header">
+	  <h1><a href="{{ root_link.link }}" title="{{ root_link.title|safe }}">{{ root_link.title|safe }}</a></h1>
 	</div><!--#ucomment-header -->
+        {% if messages %}
+        <ul>
+          {% for message in messages %}
+          <li>{{ message }}</li>
+          {% endfor %}
+        </ul>
+        {% endif %}
 
 	<div id="ucomment-navigation-top" class="ucomment-navigation">
 		<div class="ucomment-show-hide-ucomments" style="display: visible;">Hide comments<!--THIS WILL BE REPLACED BY JAVASCRIPT--></div>
 		<div class="ucomment-show-hide-ucomments" style="display: none;">Hide comments<!--THIS WILL BE REPLACED BY JAVASCRIPT--></div>
 		<div class="ucomment-nav-links">{{ nav_links|safe }}</div>
 	</div> <!--#ucomment-navigation-bottom-->
+        <div id="ucomment-navigation-admin" class="ucomment-navigation ucomment-nav-links"><a href="{{admin_link}}">Admin</a></div>
 
 	<div id="ucomment-footer">
 		This page has been accessed {{page_hits}} time{{page_hits|pluralize}}. Last updated on {{updated_on|date:"d F Y G:i"}}.
 				</div>
 			</div> <!--#ucomment-content-->
 		</div> <!--#ucomment-dialog-->
-		<div id="ucomment-dialog-footer">
+p		<div id="ucomment-dialog-footer">
 			<input id="ucomment-preview-button" class="ucomment-buttons" type="button" value="Preview your comment" tabindex="5"/>
 			<input id="ucomment-submit-button" class="ucomment-buttons" type="button" value="Submit your comment" tabindex="6"/>
 			<input id="ucomment-close-button" class="ucomment-buttons ucomment-close" type="button" value="Close" tabindex="7"/>
 
     # Dump fixtures to file for backups
     url(r'^_dump_fixtures/$', views.dump_relevent_fixtures, name='ucomment-dump-fixtures'),
+
+    # DocManager
+    url(r'^_docman/$', views.docmanpage, name="ucomment-docman"),
+
+    # Logout
+    url(r'^_logout/$', views.admin_logout, name="ucomment-logout"),
 )
 
-# DocManager
-urlpatterns += patterns('',
-                        url(r'^_docman/$', views.docmanpage, name="ucomment-docman"),
-                        )
-
 if settings.DEBUG:
 
     urlpatterns += patterns('',
 from django.core.mail import send_mail, BadHeaderError
 from django.http import HttpResponse, HttpResponseRedirect
 from django.core.urlresolvers import reverse as django_reverse
+from django.template import RequestContext
 from django.utils import simplejson            # used for XHR returns
 from django.utils import html as django_html   # used for clean search results
 
     # Finally, send this all off to the template for rendering.
     # NOTE: any additional fields added to this dictionary must also be added
     #       to the named tuple for the search page: ``def search_document(...)``
-    page_content = {'html_title': page.html_title,
+    page_content = {'header_img': conf.header_image,
+                    'html_title': page.html_title,
                     'body_html': page_body,
                     'nav_links': nav_links,
                     'root_link': root_link,
                     'stylesheet_link': conf.stylesheet_link,
+                    'admin_link': conf.admin_link,
                     'prefix_html': conf.html_prefix_text,
                     'suffix_html': conf.html_suffix_text,
                     'search_value': search_value,
     #             Update search index tables in Sphinx search
     msg = 'PUBLISH: Update and publish operation successfully completed'
     log_file.info(msg)
+#    request.user.message_set.create(message=msg)
     msg += ('<br><p>View your document <a href="%s">from this link</a>'
         '.</p>') % (django_reverse('ucomment-root'))
     return HttpResponse(msg, status=200)
+#    return HttpResponseRedirect(django_reverse('ucomment-root'))
 
 
 def call_sphinx_to_publish():
                                                      time.time() - start_time))
     return render_page_for_web(search_output, request, search)
 
+def admin_logout(request):
+    django_auth.logout(request)
+    return HttpResponseRedirect(django_reverse('ucomment-admin-signin'))
+
 def admin_signin(request):
     """
     Perform administrator/author features for the application.
     * (Re)publish the document to the web
     * Dump all fixtures to disk - for backup purposes.
     """
+    root = django_reverse('ucomment-root')
+    header_img = conf.header_image
+
     if request.user.is_authenticated():
-        msg = ('<ul>'
-               '<li><a href="%s">Table of Contents for your document</a>'
-               '<li><a href="%s">The Django admin page for your site</a>'
-               '<li><a href="%s">Publish or update the document</a>'
-               '<li><a href="%s">Add document</a>'
-               '<li>Backup your application by <a href="%s">dumping objects '
-               'to fixtures</a>') % \
-               (django_reverse('ucomment-root'),
-                django_reverse('admin:index'),
-                django_reverse('ucomment-publish-update-document'),
-                django_reverse('ucomment-docman'),
-                django_reverse('ucomment-dump-fixtures'))
-        return HttpResponse(msg, status=200)
+        return render_to_response('admin.html', {'header_img': conf.header_image,
+                                                 'root': django_reverse('ucomment-root'),
+                                                 'admidx': django_reverse('admin:index'),
+                                                 'pubupd': django_reverse('ucomment-publish-update-document'),
+                                                 'docman': django_reverse('ucomment-docman'),
+                                                 'dump': django_reverse('ucomment-dump-fixtures'),
+                                                 'logout': django_reverse('ucomment-logout'),
+                                                 }
+                                  )
+
     elif request.method == 'GET':
         log_file.info('Entering the admin section; IP = %s' % \
                                                 (get_IP_address(request)))
+
+        stylesheet_link = conf.stylesheet_link
         context = {}
         context.update(csrf(request))
-        msg = ( '<p>Please sign-in first with your Django (admin) credentials:'
-                r'<form action="%s" method="POST">{%% csrf_token %%}'
-                '<label for="username">Username:</label>'
-                '    <input type="text" name="username" /><br />'
-                '<label for="password">Password:</label>'
-                '    <input type="password" name="password" />'
-                '<input type="submit" value="Log in"></form>') % (request.path)
-        resp = template.Template(msg)
-        html_body = resp.render(template.Context(context))
-        return HttpResponse(html_body, status=200)
+
+        return render_to_response('admin_signin.html', locals())
 
     elif request.method == 'POST':
         username = request.POST.get('username', '')
 # Docman functions
 # ---------------------------------
 def docmanpage(request):
-    if request.method == "POST":
-        form = DocManForm(request.POST)
-        if form.is_valid():
-
-            # TODO: mejorar UI de formulario (y de paso de interfaz en _admin)
-
-            cd = form.cleaned_data
-            title = cd['title']
-            text = cd['text']
-
-            # Validar documento (que no haya errores en el RST)
-
-            # Sanitizar titulo
-            sanitized_title = title.replace(" ", "_")
-
-            # Verificar que no exista ya el archivo
-
-            # Agregar titulo a texto como titulo subrayado
-            text = title + "\n"+ "".join(["*" for i in range(len(title))]) + "\n\n" + text
-
-            # Guardar el documento en document_compile_area
-            added_fname = sanitized_title+".rst"
-            f = open(conf.local_repo_physical_dir + added_fname, "w")
-            f.write(text)
-            f.close()
-
-            # Agregar documento al contenido de document_compile_area/conf.master_doc
-            app = Sphinx(srcdir=conf.local_repo_physical_dir,
-                         confdir=conf.local_repo_physical_dir,
-                         outdir = '/tmp', doctreedir = '/tmp',
-                         buildername = 'pickle')
-            master_doc = app.env.config.master_doc + ".rst"
-
-            f = open(conf.local_repo_physical_dir + master_doc, "r")
-            lines = f.read()
-            f.close
-
-            lines = lines.split('\n')
-            idx = lines.index('.. toctree::') + 3
-            while idx < len(lines) and lines[idx] is not "":
-                idx = idx + 1
-            lines.insert(idx, '   ' + sanitized_title)
-            
-            f = open(conf.local_repo_physical_dir + master_doc, "w")
-            f.write("\n".join(lines))
-            f.close()
-
-            # Mandar cambios al repositorio
-            dvcs.add('', added_fname)
-            commit_to_repo_and_push("Documento agregado: " + sanitized_title)
-
-            # Publicar automaticamente
-            return HttpResponseRedirect(django_reverse('ucomment-publish-update-document'))
-    else:
-        form = DocManForm()
-
-    return render_to_response('docman/docmanpage_form.html', {'form': form})
+    if request.user.is_authenticated():
+        if request.method == "POST":
+            form = DocManForm(request.POST)
+            form.fname_dir = conf.local_repo_physical_dir
+            if form.is_valid():
+
+                # TODO: improve form UI (and also _admin interface)
+
+                cd = form.cleaned_data
+                title = cd['title']
+                text = cd['text']
+
+                # Add title to text, as an underlined title
+                text = title + "\n"+ "".join(["*" for i in range(len(title))]) + "\n\n" + text
+
+                # Save documento at document_compile_area
+                try:
+                    f = open(conf.local_repo_physical_dir + form.added_fname, "w")
+                    f.write(text)
+                    f.close()
+                    log_file.info('Added file created: ' + form.added_fname)
+                except:
+                    log_file.error('Added file creation failed! (%s)' % form.added_fname)
+                    request.user.message_set.create(message="Error al crear el archivo!")
+                    return HttpResponseRedirect(django_reverse('ucomment-docman'))
+
+                # Add document at index in document_compile_area/conf.master_doc
+                try:
+                    app = Sphinx(srcdir=conf.local_repo_physical_dir,
+                                 confdir=conf.local_repo_physical_dir,
+                                 outdir = '/tmp', doctreedir = '/tmp',
+                                 buildername = 'pickle')
+                except:
+                    log_file.error('Sphinx parameter loading failed!')
+                    request.user.message_set.create(message="Error al cargar parametros!")
+                    return HttpResponseRedirect(django_reverse('ucomment-docman'))
+                master_doc = app.env.config.master_doc + ".rst"
+
+                try:
+                    f = open(conf.local_repo_physical_dir + master_doc, "r")
+                    lines = f.read()
+                    f.close
+                except:
+                    log_file.error('Reading contents file failed!')
+                    request.user.message_set.create(message="Error al leer el contenido!")
+                    return HttpResponseRedirect(django_reverse('ucomment-docman'))
+
+                lines = lines.split('\n')
+                idx = lines.index('.. toctree::') + 3
+                while idx < len(lines) and lines[idx] is not "":
+                    idx = idx + 1
+                lines.insert(idx, '   ' + form.sanitized_title)
+
+                try:
+                    f = open(conf.local_repo_physical_dir + master_doc, "w")
+                    f.write("\n".join(lines))
+                    f.close()
+                    log_file.info('Contents file updated')
+                except:
+                    log_file.error('Writing contents file failed!')
+                    request.user.message_set.create(message="Error al escribir el contenido!")
+                    return HttpResponseRedirect(django_reverse('ucomment-docman'))
+
+                # Send changes to repo
+                dvcs.add('', form.added_fname)
+                commit_to_repo_and_push("Documento agregado: " + form.sanitized_title)
+                log_file.info('Repo updated!')
+
+                # Automatically publish...
+                return HttpResponseRedirect(django_reverse('ucomment-publish-update-document'))
+        else:
+            form = DocManForm()
+
+        return render_to_response('docmanpage_form.html', {'form': form}, context_instance=RequestContext(request))
+
+    elif request.method == 'GET':
+        root = django_reverse('ucomment-root')
+        header_img = conf.header_image
+
+        log_file.info('Entering the admin section; IP = %s' % \
+                                                (get_IP_address(request)))
+        context = {}
+        context.update(csrf(request))
+        return render_to_response('admin_signin.html', locals())
+
+    elif request.method == 'POST':
+        username = request.POST.get('username', '')
+        password = request.POST.get('password', '')
+        user = django_auth.authenticate(username=username, password=password)
+        if user is not None and user.is_active:
+            django_auth.login(request, user)
+            return HttpResponseRedirect(request.path)
+        else:
+            # TODO(KGD): respond that user does not exist, or that password
+            #            is incorrect;  redirect to log in page again.
+            return HttpResponseRedirect(request.path)