Skip to content

Commit

Permalink
saving the support request on the site
Browse files Browse the repository at this point in the history
close #62
  • Loading branch information
fredriknilson committed Mar 26, 2012
1 parent 41a7a2b commit d98277b
Show file tree
Hide file tree
Showing 10 changed files with 285 additions and 0 deletions.
1 change: 1 addition & 0 deletions voteit/site/__init__.py
Expand Up @@ -6,4 +6,5 @@
def includeme(config):
""" Include Site adapter and register views."""
config.scan('voteit.site')
config.include('voteit.site.models.support_storage')
config.add_translation_dirs('voteit.site:locale/')
Empty file added voteit/site/models/__init__.py
Empty file.
27 changes: 27 additions & 0 deletions voteit/site/models/interfaces.py
@@ -0,0 +1,27 @@
from zope.interface import Interface
from zope.interface import Attribute


class ISupportStorage(Interface):
""" An adapter for sites that handle storage of support requests. """
support_storage = Attribute("Conatins the support request saved on the site")

def __init__(context):
""" Object needs a meeting to adapt. """

def add(message, subject='', name='', email='', meeting=None):
""" Add a support request.
"""

class ISupportRequest(Interface):
""" A persistent support request. """
created = Attribute("When it was created, in UTC time.")
message = Attribute("The message.")
subject = Attribute("The subject.")
name = Attribute("The name specified.")
email = Attribute("The email specified.")
meeting = Attribute("The meeting the user was on if any.")

def __init__(message, subject='', name='', email='', meeting=None):
""" Create a support request.
"""
66 changes: 66 additions & 0 deletions voteit/site/models/support_storage.py
@@ -0,0 +1,66 @@
from zope.component import adapts
from zope.interface import implements
from persistent import Persistent
from BTrees.LOBTree import LOBTree
from betahaus.pyracont.decorators import content_factory
from betahaus.pyracont.factories import createContent

from voteit.core.models.date_time_util import utcnow
from voteit.core.models.interfaces import ISiteRoot

from voteit.site.models.interfaces import ISupportStorage
from voteit.site.models.interfaces import ISupportRequest
from voteit.site import SiteMF as _


class SupportStorage(object):
""" An adapter for ISiteRoot that handle feed entries.
"""
implements(ISupportStorage)

def __init__(self, context):
self.context = context

@property
def support_storage(self):
if not hasattr(self.context, '__support_storage__'):
self.context.__support_storage__ = LOBTree()
return self.context.__support_storage__

def _next_free_key(self):
if len(self.support_storage) == 0:
return 0
return self.support_storage.maxKey()+1

def add(self, message, subject='', name='', email='', meeting=None):
""" Add a support request.
"""
obj = createContent('SupportRequest', message, subject=subject, name=name, email=email, meeting=meeting)

for i in range(10):
k = self._next_free_key()
if self.support_storage.insert(k, obj):
return

raise KeyError("Couln't find a free key for support request after 10 retries.") # pragma : no cover


@content_factory('SupportRequest', title=_(u"Support request"))
class SupportRequest(Persistent):
implements(ISupportRequest)

def __init__(self, message, subject='', name='', email='', meeting=None):
self.created = utcnow()
self.message = message
self.subject = subject
self.name = name
self.email = email
self.meeting = meeting


def includeme(config):
""" Include to activate support storage components.
like: config.include('voteit.site.models.support_storage')
"""
#Register SupportRequest adapter
config.registry.registerAdapter(SupportStorage, (ISiteRoot,), ISupportStorage)
Empty file.
94 changes: 94 additions & 0 deletions voteit/site/models/tests/test_support_storage.py
@@ -0,0 +1,94 @@
import unittest
from datetime import datetime

from pyramid import testing
from zope.interface.verify import verifyObject
from zope.component.interfaces import IFactory
from zope.component import createObject


class SupportStorageTests(unittest.TestCase):

def setUp(self):
self.request = testing.DummyRequest()
self.config = testing.setUp(request=self.request)
self.config.testing_securitypolicy(userid='some_user',
permissive=True)

def tearDown(self):
testing.tearDown()

def _make_adapted_obj(self):
from voteit.core.models.site import SiteRoot
from voteit.site.models.support_storage import SupportStorage
context = SiteRoot()
return SupportStorage(context)

def _register_support_request_factory(self):
#FIXME: Detach more?
self.config.scan('voteit.site.models.support_storage')

def test_interface(self):
from voteit.site.models.interfaces import ISupportStorage
obj = self._make_adapted_obj()
self.assertTrue(verifyObject(ISupportStorage, obj))

def test_add(self):
self._register_support_request_factory()
obj = self._make_adapted_obj()
meeting = object()
obj.add('message', subject='subject', name='name', email='email', meeting=meeting)

self.assertEqual(len(obj.support_storage), 1)
self.assertEqual(obj.support_storage[0].message, 'message')
self.assertEqual(obj.support_storage[0].subject, 'subject')
self.assertEqual(obj.support_storage[0].name, 'name')
self.assertEqual(obj.support_storage[0].email, 'email')
self.assertEqual(obj.support_storage[0].meeting, meeting)

def test_registration_on_include(self):
self.config.include('voteit.site.models.support_storage')
from voteit.core.models.site import SiteRoot
root = SiteRoot()
from voteit.site.models.interfaces import ISupportStorage
adapter = self.config.registry.queryAdapter(root, ISupportStorage)
self.failUnless(ISupportStorage.providedBy(adapter))


class FeedEntryTests(unittest.TestCase):

def setUp(self):
self.config = testing.setUp()

def tearDown(self):
testing.tearDown()

@property
def _cut(self):
from voteit.site.models.support_storage import SupportRequest
return SupportRequest

def test_interface(self):
from voteit.site.models.interfaces import ISupportRequest
obj = self._cut('message')
self.assertTrue(verifyObject(ISupportRequest, obj))

def test_construction(self):
meeting = object()
obj = self._cut('message', subject='subject', name='name', email='email', meeting=meeting)
self.assertTrue(isinstance(obj.created, datetime))
self.assertEqual(obj.message, 'message')
self.assertEqual(obj.subject, 'subject')
self.assertEqual(obj.name, 'name')
self.assertEqual(obj.email, 'email')
self.assertEqual(obj.meeting, meeting)

def test_factory_registered_on_scan(self):
self.config.scan('voteit.site.models.support_storage')

factory = self.config.registry.queryUtility(IFactory, 'SupportRequest')
self.failUnless(IFactory.providedBy(factory))
obj = factory('message')
self.failUnless(obj)
obj = createObject('SupportRequest', 'message')
self.failUnless(obj)
12 changes: 12 additions & 0 deletions voteit/site/views/components/meeting_actions.py
@@ -0,0 +1,12 @@
from pyramid.url import resource_url
from betahaus.viewcomponent import view_action

from voteit.site import SiteMF as _


@view_action('admin_menu', 'support requests', title = _(u"Support requests"), link = "support_requests")
def generic_root_menu_link(context, request, va, **kw):
""" This is for simple menu items for the root """
api = kw['api']
url = api.resource_url(api.root, request) + va.kwargs['link']
return """<li><a href="%s">%s</a></li>""" % (url, api.translate(va.title))
7 changes: 7 additions & 0 deletions voteit/site/views/help.py
Expand Up @@ -9,6 +9,7 @@
from pyramid.response import Response
from pyramid_mailer import get_mailer
from pyramid_mailer.message import Message
from pyramid.traversal import find_root
from betahaus.pyracont.factories import createSchema

from voteit.core import security
Expand All @@ -20,6 +21,7 @@
from voteit.core import fanstaticlib

from voteit.site import SiteMF as _
from voteit.site.models.interfaces import ISupportStorage


class HelpView(BaseView):
Expand Down Expand Up @@ -114,6 +116,11 @@ def support(self):

mailer = get_mailer(self.request)
mailer.send(msg)

# add the message to the support storage
root = find_root(self.context)
support_storage = self.request.registry.getAdapter(root, ISupportStorage)
support_storage.add(appstruct['message'], subject=appstruct['subject'], name=appstruct['name'], email=appstruct['email'], meeting=self.api.meeting)

self.response['message'] = _(u"Message sent to VoteIT")
return Response(render("templates/ajax_success.pt", self.response, request = self.request))
Expand Down
19 changes: 19 additions & 0 deletions voteit/site/views/support_request.py
@@ -0,0 +1,19 @@
from pyramid.view import view_config

from voteit.core import security
from voteit.core.models.interfaces import ISiteRoot
from voteit.core.views.base_view import BaseView

from voteit.site import SiteMF as _
from voteit.site.models.interfaces import ISupportStorage


class SupportView(BaseView):
@view_config(name = 'support_requests', context=ISiteRoot, renderer="templates/support_requests.pt", permission=security.MANAGE_SERVER, )
def support_requests(self):

adapter = self.request.registry.getAdapter(self.context, ISupportStorage)

self.response['support_storage'] = adapter.support_storage.values()

return self.response
59 changes: 59 additions & 0 deletions voteit/site/views/templates/support_requests.pt
@@ -0,0 +1,59 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
xmlns:tal="http://xml.zope.org/namespaces/tal"
metal:use-macro="api.main_template.macros['master']"
xmlns:i18n="http://xml.zope.org/namespaces/i18n"
i18n:domain="voteit.core">
<body>
<div metal:fill-slot="content" class="content_wrapper">

<h3 i18n:translate="">
Showing
<span tal:replace="len(support_storage)" i18n:name="count">5</span>
support requests
</h3>

<table class="listing">
<thead>
<tr>
<th i18n:translate="" class="heading">Created</th>
<th i18n:translate="" class="heading">Subject</th>
<th i18n:translate="" class="heading">Message</th>
<th i18n:translate="" class="heading">Name</th>
<th i18n:translate="" class="heading">Email</th>
<th i18n:translate="" class="heading">Meeting</th>
</tr>
</thead>
<tbody>
<tal:iterate repeat="support_request support_storage">
<tr tal:attributes="class repeat.support_request.odd and 'odd' or 'even'">
<td tal:content="api.dt_util.dt_format(support_request.created)|string:-">Created</td>
<td tal:content="support_request.subject">Subject</td>
<td tal:content="support_request.message">Message</td>
<td tal:content="support_request.name">Name</td>
<td>
<a tal:condition="support_request.email" tal:content="support_request.email"
tal:attributes="href 'mailto:%s' % support_request.email">
email
</a>
</td>
<td>
<a tal:condition="support_request.meeting" tal:content="support_request.meeting"
href="${api.resource_url(support_request.meeting, request)}">
Meeting
</a>
</td>
</tr>
</tal:iterate>
</tbody>
</table>
<br/>
<a class="buttonize large"
tal:attributes="href api.resource_url(context, request)">
<span i18n:translate="">Back</span>
</a><br/>

</div> <!-- content -->
</body>
</html>

0 comments on commit d98277b

Please sign in to comment.