Add support for sending new messages.
This commit is contained in:
parent
9d802d8f25
commit
687b83e2e1
9 changed files with 228 additions and 18 deletions
|
@ -2,7 +2,7 @@
|
|||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2014 Lance Edgar
|
||||
# Copyright © 2010-2016 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
|
@ -20,11 +20,12 @@
|
|||
# along with Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
|
||||
"""
|
||||
Autocomplete View
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
from tailbone.views.core import View
|
||||
from tailbone.db import Session
|
||||
|
||||
|
@ -73,4 +74,4 @@ class AutocompleteView(View):
|
|||
if not term:
|
||||
return []
|
||||
results = self.query(term).all()
|
||||
return [{u'label': self.display(x), u'value': self.value(x)} for x in results]
|
||||
return [{'label': self.display(x), 'value': self.value(x)} for x in results]
|
||||
|
|
|
@ -103,6 +103,7 @@ class MasterView(View):
|
|||
form = self.make_form(self.model_class)
|
||||
if self.request.method == 'POST':
|
||||
if form.validate():
|
||||
self.before_create(form)
|
||||
form.save()
|
||||
instance = form.fieldset.model
|
||||
self.after_create(instance)
|
||||
|
@ -549,6 +550,12 @@ class MasterView(View):
|
|||
"""
|
||||
fieldset.configure()
|
||||
|
||||
def before_create(self, form):
|
||||
"""
|
||||
Event hook, called just after the form to create a new instance has
|
||||
been validated, but prior to the form itself being saved.
|
||||
"""
|
||||
|
||||
def after_create(self, instance):
|
||||
"""
|
||||
Event hook, called just after a new instance is saved.
|
||||
|
|
|
@ -30,12 +30,13 @@ from rattail import enum
|
|||
from rattail.db import model
|
||||
|
||||
import formalchemy
|
||||
from formalchemy.helpers import hidden_field
|
||||
from pyramid import httpexceptions
|
||||
from webhelpers.html import tags
|
||||
from webhelpers.html import tags, HTML
|
||||
|
||||
from tailbone import forms
|
||||
from tailbone.db import Session
|
||||
from tailbone.views import MasterView
|
||||
from tailbone.views import MasterView, AutocompleteView
|
||||
|
||||
|
||||
class SubjectFieldRenderer(formalchemy.FieldRenderer):
|
||||
|
@ -56,13 +57,31 @@ class SenderFieldRenderer(forms.renderers.UserFieldRenderer):
|
|||
return super(SenderFieldRenderer, self).render_readonly(**kwargs)
|
||||
|
||||
|
||||
class RecipientsField(formalchemy.Field):
|
||||
"""
|
||||
Custom field for recipients, used when sending new messages.
|
||||
"""
|
||||
is_collection = True
|
||||
|
||||
def sync(self):
|
||||
if not self.is_readonly():
|
||||
message = self.parent.model
|
||||
for uuid in set(self._deserialize()):
|
||||
user = Session.query(model.User).get(uuid)
|
||||
if user:
|
||||
message.add_recipient(user, status=enum.MESSAGE_STATUS_INBOX)
|
||||
|
||||
|
||||
class RecipientsFieldRenderer(formalchemy.FieldRenderer):
|
||||
|
||||
def render(self, **kwargs):
|
||||
return HTML.tag('ul')
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
recipients = self.raw_value
|
||||
if not recipients:
|
||||
return ''
|
||||
recips = filter(lambda r: r.recipient is not self.request.user, recipients)
|
||||
recips = [r for r in recipients if r.recipient is not self.request.user]
|
||||
recips = sorted([r.recipient.display_name for r in recips])
|
||||
if len(recips) < len(recipients):
|
||||
recips.insert(0, 'you')
|
||||
|
@ -87,7 +106,6 @@ class MessagesView(MasterView):
|
|||
Base class for message views.
|
||||
"""
|
||||
model_class = model.Message
|
||||
creatable = False
|
||||
editable = False
|
||||
deletable = False
|
||||
checkboxes = True
|
||||
|
@ -151,16 +169,27 @@ class MessagesView(MasterView):
|
|||
return {}
|
||||
|
||||
def configure_fieldset(self, fs):
|
||||
fs.configure(
|
||||
include=[
|
||||
if self.creating:
|
||||
fs.append(RecipientsField('recipients', label="To", renderer=RecipientsFieldRenderer))
|
||||
fs.configure(include=[
|
||||
fs.recipients,
|
||||
fs.subject,
|
||||
fs.body.textarea(size='50x10'),
|
||||
])
|
||||
else:
|
||||
fs.configure(include=[
|
||||
fs.sender.with_renderer(SenderFieldRenderer).label("From"),
|
||||
fs.recipients.with_renderer(RecipientsFieldRenderer).label("To"),
|
||||
fs.sent.with_renderer(forms.renderers.DateTimeFieldRenderer(self.rattail_config)),
|
||||
fs.body,
|
||||
fs.subject,
|
||||
fs.body.textarea(size='50x10'),
|
||||
])
|
||||
if self.viewing:
|
||||
del fs.body
|
||||
del fs.body # ..really?
|
||||
|
||||
def before_create(self, form):
|
||||
message = form.fieldset.model
|
||||
message.sender = self.request.user
|
||||
|
||||
def get_recipient(self, message):
|
||||
for recip in message.recipients:
|
||||
|
@ -265,6 +294,22 @@ class SentView(MessagesView):
|
|||
g.filters['sender'].default_active = False
|
||||
|
||||
|
||||
class RecipientsAutocomplete(AutocompleteView):
|
||||
"""
|
||||
Autocomplete AJAX view for the recipients field when sending a new message.
|
||||
"""
|
||||
|
||||
def query(self, term):
|
||||
return Session.query(model.User)\
|
||||
.join(model.Person)\
|
||||
.filter(model.User.active == True)\
|
||||
.filter(model.Person.display_name.ilike('%{}%'.format(term)))\
|
||||
.order_by(model.Person.display_name)
|
||||
|
||||
def display(self, user):
|
||||
return user.person.display_name
|
||||
|
||||
|
||||
def includeme(config):
|
||||
|
||||
config.add_tailbone_permission('messages', 'messages.list', "List/Search Messages")
|
||||
|
@ -279,6 +324,10 @@ def includeme(config):
|
|||
config.add_view(ArchiveView, attr='index', route_name='messages.archive',
|
||||
permission='messages.list')
|
||||
|
||||
# move (single)
|
||||
config.add_route('messages.move', '/messages/{uuid}/move')
|
||||
config.add_view(MessagesView, attr='move', route_name='messages.move')
|
||||
|
||||
# move bulk
|
||||
config.add_route('messages.move_bulk', '/messages/move-bulk')
|
||||
config.add_view(MessagesView, attr='move_bulk', route_name='messages.move_bulk')
|
||||
|
@ -288,10 +337,9 @@ def includeme(config):
|
|||
config.add_view(SentView, attr='index', route_name='messages.sent',
|
||||
permission='messages.list')
|
||||
|
||||
# view
|
||||
config.add_route('messages.view', '/messages/{uuid}')
|
||||
config.add_view(MessagesView, attr='view', route_name='messages.view')
|
||||
# recipients autocomplete
|
||||
config.add_route('messages.recipients', '/messages/recipients')
|
||||
config.add_view(RecipientsAutocomplete, route_name='messages.recipients',
|
||||
renderer='json', permission='messages.create')
|
||||
|
||||
# move (single)
|
||||
config.add_route('messages.move', '/messages/{uuid}/move')
|
||||
config.add_view(MessagesView, attr='move', route_name='messages.move')
|
||||
MessagesView.defaults(config)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue