diff --git a/pandora/0xdb.jsonc b/pandora/0xdb.jsonc index fa5e70560..56c728881 100644 --- a/pandora/0xdb.jsonc +++ b/pandora/0xdb.jsonc @@ -25,7 +25,8 @@ "canSeeDebugMenu": {"staff": true, "admin": true}, "canSeeFiles": {"staff": true, "admin": true}, "canSeeItem": {"guest": 3, "member": 3, "friend": 4, "staff": 4, "admin": 4}, - "canSeeExtraItemViews": {"friend": true, "staff": true, "admin": true} + "canSeeExtraItemViews": {"friend": true, "staff": true, "admin": true}, + "canSendMail": {"staff": true, "admin": true} }, /* clipKeys are the properties that clips can by sorted by. @@ -549,9 +550,12 @@ ], "sendReferrer": false, "site": { + // FIXME: "from" and "to" would be more intuitive as keys here "email": { // E-mail address in contact form (to) "contact": "0xdb@0xdb.org", + "footer": "-- \n0xDB - http://0xdb.org", + "prefix": "0xDB Newsletter -", // E-mail address uses by the system (from) "system": "0xdb@0xdb.org" }, diff --git a/pandora/padma.jsonc b/pandora/padma.jsonc index 98e1a1fd8..712288306 100644 --- a/pandora/padma.jsonc +++ b/pandora/padma.jsonc @@ -461,6 +461,8 @@ "email": { // E-mail address in contact form (to) "contact": "pad.ma@pad.ma", + "footer": "-- \nPad.ma - http://pad.ma", + "prefix": "Pad.ma Newsletter -", // E-mail address uses by the system (from) "system": "system@pad.ma" }, diff --git a/pandora/user/models.py b/pandora/user/models.py index d940e57e2..a60e44e0b 100644 --- a/pandora/user/models.py +++ b/pandora/user/models.py @@ -135,6 +135,7 @@ class SessionData(models.Model): 'lastseen': self.lastseen, 'level': 'guest', 'location': self.location, + 'newsletter': False, 'notes': '', 'numberoflists': 0, 'screensize': self.screensize, @@ -149,6 +150,7 @@ class SessionData(models.Model): j['disabled'] = not self.user.is_active j['email'] = self.user.email j['level'] = p.get_level() + j['newsletter'] = p.newsletter j['notes'] = p.notes j['numberoflists'] = self.user.lists.count() if keys: @@ -263,6 +265,7 @@ def init_user(user, request=None): result['level'] = profile.get_level() result['groups'] = [g.name for g in user.groups.all()] result['email'] = user.email + result['newsletter'] = profile.newsletter result['ui'] = profile.get_ui() result['volumes'] = [v.json() for v in user.volumes.all()] return result @@ -276,6 +279,7 @@ def user_json(user, keys=None): 'id': ox.to26(user.id), 'lastseen': user.last_login, 'level': p.get_level(), + 'newsletter': p.newsletter, 'notes': p.notes, 'numberoflists': user.lists.count(), 'username': user.username, diff --git a/pandora/user/templates/contact_email.txt b/pandora/user/templates/contact_email.txt index f50c8bfa1..592e71899 100644 --- a/pandora/user/templates/contact_email.txt +++ b/pandora/user/templates/contact_email.txt @@ -3,5 +3,4 @@ Subject: {{subject}} {{message}} --- -{{sitename}} - {{url}} +{{footer}} diff --git a/pandora/user/templates/contact_receipt.txt b/pandora/user/templates/contact_receipt.txt index a2f4b159f..cca54ca40 100644 --- a/pandora/user/templates/contact_receipt.txt +++ b/pandora/user/templates/contact_receipt.txt @@ -4,5 +4,4 @@ Subject: {{subject}} {{message}} --- -{{sitename}} - {{url}} +{{footer}} diff --git a/pandora/user/templates/mailout_receipt.txt b/pandora/user/templates/mailout_receipt.txt new file mode 100644 index 000000000..4517652fa --- /dev/null +++ b/pandora/user/templates/mailout_receipt.txt @@ -0,0 +1,4 @@ +To: {{to|safe}} +Subject: {{subject|safe}} + +{{message|safe}} diff --git a/pandora/user/templates/password_reset_email.txt b/pandora/user/templates/password_reset_email.txt index 1f39ceca3..4603261b1 100644 --- a/pandora/user/templates/password_reset_email.txt +++ b/pandora/user/templates/password_reset_email.txt @@ -4,5 +4,4 @@ To reset your password, please use the following code: If you don't want to reset your password, no further action is required. --- -{{sitename}} - {{url}} +{{footer}} diff --git a/pandora/user/views.py b/pandora/user/views.py index ab87dfdf7..499a4d5d3 100644 --- a/pandora/user/views.py +++ b/pandora/user/views.py @@ -4,12 +4,11 @@ import random random.seed() import re -from django.contrib.auth.models import User from django.contrib.auth import authenticate, login, logout from django.template import RequestContext, loader from django.utils import simplejson as json from django.conf import settings -from django.core.mail import send_mail, BadHeaderError +from django.core.mail import send_mail, BadHeaderError, EmailMessage from django.db.models import Sum from django.shortcuts import redirect @@ -280,6 +279,7 @@ def requestToken(request): context = RequestContext(request, { 'code': code, 'sitename': settings.SITENAME, + 'footer': settings.CONFIG['site']['email']['footer'], 'url': request.build_absolute_uri('/'), }) message = template.render(context) @@ -333,6 +333,8 @@ def editUser(request): profile.set_level(data['level']) if 'notes' in data: profile.notes = data['notes'] + if 'newsletter' in data: + profile.newsletter = data['newsletter'] if 'username' in data: if models.User.objects.filter(username=data['username']).exclude(id=user.id).count()>0: response = json_response(status=403, text='username already in use') @@ -388,10 +390,10 @@ def findUser(request): if data['key'] == 'email': response['data']['users'] = [models.user_json(u, keys) - for u in User.objects.filter(email__iexact=data['value'])] + for u in models.User.objects.filter(email__iexact=data['value'])] else: response['data']['users'] = [models.user_json(u, keys) - for u in User.objects.filter(username__iexact=data['value'])] + for u in models.User.objects.filter(username__iexact=data['value'])] return render_to_json_response(response) actions.register(findUser) @@ -527,6 +529,71 @@ Positions return render_to_json_response(response) actions.register(findUsers) +@login_required_json +def mail(request): + ''' + param data { + 'to': array of usernames, + 'subject': string, + 'message': string + } + + message can contain {username} or {email}, + this will be replace with the user/email + the mail is sent to. + + return { + 'status': {'code': int, 'text': string} + } + ''' + response = json_response() + data = json.loads(request.POST['data']) + p = request.user.get_profile() + if p.capability('canSendMail'): + email_from = '"%s" <%s>' % (settings.SITENAME, settings.CONFIG['site']['email']['system']) + headers = { + 'Reply-To': settings.CONFIG['site']['email']['contact'] + } + subject = data.get('subject', '').strip() + users = [models.User.objects.get(username=username) for username in data['to']] + for user in users: + if user.email: + message = data['message'] + for key, value in ( + ('{username}', user.username), + ('{email}', user.email), + ): + message = message.replace(key, value) + email_to = '"%s" <%s>' % (user.username, user.email) + email = EmailMessage(subject, + message, + email_from, + [email_to], + headers = headers) + email.send(fail_silently=True) + if 'receipt' in data \ + and data['receipt']: + template = loader.get_template('mailout_receipt.txt') + context = RequestContext(request, { + 'footer': settings.CONFIG['site']['email']['footer'], + 'to': ', '.join(['"%s" <%s>' % (u.username, u.email) for u in users]), + 'subject': subject, + 'message': data['message'], + 'url': request.build_absolute_uri('/'), + }) + message = template.render(context) + subject = u'Fwd: %s' % subject + email_to = '"%s" <%s>' % (request.user.username, request.user.email) + receipt = EmailMessage(subject, + message, + email_from, + [email_to]) + receipt.send(fail_silently=True) + response = json_response(text='message sent') + else: + response = json_response(status=403, text='not allowed to send mail') + return render_to_json_response(response) +actions.register(mail, cache=False) def contact(request): ''' @@ -549,7 +616,7 @@ def contact(request): if not email: email = request.user.email if 'message' in data and data['message'].strip(): - email_from = settings.CONFIG['site']['email']['system'] + email_from = '"%s" <%s>' % (settings.SITENAME, settings.CONFIG['site']['email']['system']) email_to = [settings.CONFIG['site']['email']['contact'], ] subject = data.get('subject', '').strip() template = loader.get_template('contact_email.txt') @@ -559,12 +626,13 @@ def contact(request): 'subject': subject, 'message': data['message'].strip(), 'sitename': settings.SITENAME, + 'footer': settings.CONFIG['site']['email']['footer'], 'url': request.build_absolute_uri('/'), }) message = template.render(context) response = json_response(text='message sent') try: - send_mail(u'[%s Contact] %s' % (settings.SITENAME, subject), message, email_from, email_to) + send_mail(u'%s Contact - %s' % (settings.SITENAME, subject), message, email_from, email_to) except BadHeaderError: response = json_response(status=400, text='invalid data') if request.user.is_authenticated() \ @@ -575,6 +643,7 @@ def contact(request): 'name': name, 'from': email, 'sitename': settings.SITENAME, + 'footer': settings.CONFIG['site']['email']['footer'], 'to': email_to[0], 'subject': subject, 'message': data['message'].strip(), @@ -618,6 +687,10 @@ def editPreferences(request): else: change = True request.user.email = data['email'] + if 'newsletter' in data: + profile = request.user.get_profile() + profile.newsletter = data['newsletter'] + profile.save() if 'password' in data: change = True request.user.set_password(data['password']) diff --git a/static/js/pandora/preferencesDialog.js b/static/js/pandora/preferencesDialog.js index d7d784391..befd2dc55 100644 --- a/static/js/pandora/preferencesDialog.js +++ b/static/js/pandora/preferencesDialog.js @@ -83,6 +83,28 @@ pandora.ui.preferencesDialog = function() { }) ); } else { + $content.append( + Ox.Checkbox({ + checked: pandora.user.newsletter, + id: 'newsletter', + label: 'Newsletter', + labelWidth: 80, + title: pandora.user.newsletter ? 'Subscribed' : 'Unsubscribed', + width: 240 + }) + .bindEvent({ + change: function(data) { + this.options({ + title: this.options('title') == 'Subscribed' ? 'Unsubscribed' : 'Subscribed' + }); + pandora.user.newsletter = data.checked; + pandora.api.editPreferences({ + newsletter: pandora.user.newsletter + }); + } + }) + .css({position: 'absolute', left: '96px', top: '16px'}) + ); $content.append( Ox.Button({ title: 'Reset UI Settings', @@ -94,26 +116,8 @@ pandora.ui.preferencesDialog = function() { pandora.$ui.appPanel.reload(); } }) - .css({position: 'absolute', left: '96px', top: '16px'}) + .css({position: 'absolute', left: '96px', top: '46px'}) ); - /* - content.append(Ox.FormElementGroup({ - elements: [ - Ox.Checkbox({ - checked: true , - id: 'showEpisodes', - title: 'Show Episodes', - width: 320 - }), - Ox.Checkbox({ - checked: true , - id: 'newsletter', - title: 'Receive Newsletter', - width: 320 - }) - ] - })); - */ } return $content; }, @@ -127,7 +131,7 @@ pandora.ui.preferencesDialog = function() { }).bindEvent({ click: function() { $dialog.close(); - pandora.URL.update(); + pandora.UI.set({page: ''}); } }) ], diff --git a/static/js/pandora/usersDialog.js b/static/js/pandora/usersDialog.js index 755cb664f..1a7c33e34 100644 --- a/static/js/pandora/usersDialog.js +++ b/static/js/pandora/usersDialog.js @@ -4,8 +4,9 @@ pandora.ui.usersDialog = function() { - var height = Math.round((window.innerHeight - 48) * 0.9), - width = Math.round(window.innerWidth * 0.9), + var dialogHeight = Math.round((window.innerHeight - 48) * 0.9), + dialogWidth = Math.round(window.innerWidth * 0.9), + formWidth = 256, numberOfUsers = 0, userLevels = ['member', 'friend', 'staff', 'admin'], @@ -77,9 +78,8 @@ pandora.ui.usersDialog = function() { }, id: 'disabled', operator: '-', - title: $('').attr({ - src: Ox.UI.getImageURL('symbolCheck') - }), + title: 'Enabled', + titleImage: 'check', visible: true, width: 16 }, @@ -126,6 +126,26 @@ pandora.ui.usersDialog = function() { visible: true, width: 60 }, + { + format: function(value) { + return $('') + .attr({ + src: Ox.UI.getImageURL('symbolMail') + }) + .css({ + width: '10px', + height: '10px', + padding: '3px', + opacity: +value + }); + }, + id: 'newsletter', + title: 'Newsletter', + titleImage: 'mail', + operator: '-', + visible: true, + width: 16 + }, { id: 'numberoflists', align: 'right', @@ -222,7 +242,7 @@ pandora.ui.usersDialog = function() { columnsVisible: true, items: pandora.api.findUsers, keys: ['notes'], - max: 1, + max: -1, scrollbarVisible: true, sort: [{key: 'lastseen', operator: '-'}] }) @@ -241,135 +261,156 @@ pandora.ui.usersDialog = function() { ) ); }, - select: function(data) { - var values; - $user.empty(); - if (data.ids.length) { - values = $list.value(data.ids[0]); - if(values.level != 'guest') { - $userLabel.options({ - title: values.username + ' <' + values.email + '>' - }); - $user.append(renderUserForm(values)); - } else { - $userLabel.options({title: 'Guest'}); - } - } else { - $userLabel.options({title: 'No user selected'}); - } - } + select: selectUsers }), - $userLabel = Ox.Label({ + $formLabel = Ox.Label({ textAlign: 'center', title: 'No user selected', - width: 248 + width: 212 }) - .css({margin: '4px'}), + .css({float: 'left', margin: '4px 2px 4px 4px'}), - $user = Ox.Element({}), - - that = Ox.Dialog({ - buttons: [ - Ox.Button({ - title: 'Export E-Mail Addresses' - }) - .css({margin: '4px 4px 4px 0'}) - .bindEvent({ - click: function() { - pandora.api.findUsers({ - query: {conditions: [], operator: '&'}, - keys: ['email', 'username'], - range: [0, numberOfUsers], - sort: [{key: 'username', operator: '+'}] - }, function(result) { - var $dialog = Ox.Dialog({ - buttons: [ - Ox.Button({ - title: 'Close' - }) - .bindEvent({ - click: function() { - $dialog.close(); - } - }) - ], - content: Ox.Element() - .addClass('OxSelectable') - .css({margin: '16px'}) - .html( - result.data.items.filter(function(item) { - return item.email; - }).map(function(item) { - return item.username + ' <' + item.email + '>'; - }).join(', ') - ), - removeOnClose: true, - title: 'E-Mail Addresses' - }) - .open(); - }); - } - }), - Ox.Button({ - id: 'done', - title: 'Done', - width: 48 - }).bindEvent({ - click: function() { - Ox.Request.clearCache('findUsers'); - that.close(); - } - }) - ], - closeButton: true, - content: Ox.SplitPanel({ - elements: [ + $formButton = Ox.ButtonGroup({ + buttons: [ { - element: Ox.SplitPanel({ + id: 'edit', + selected: true, + title: 'edit', + tooltip: 'Edit' + }, + { + id: 'mail', + title: 'mail', + tooltip: 'Mail' + } + ], + selectable: true, + type: 'image' + }) + .css({float: 'left', margin: '4px 4px 4px 2px'}) + .bindEvent({ + change: selectForm + }), + + $form = Ox.Element({}), + + $editForm, + + $mailForm = renderMailForm(), + + $content = Ox.SplitPanel({ + elements: [ + { + element: Ox.SplitPanel({ + elements: [ + { + element: Ox.Bar({size: 24}) + .append($guestsCheckbox) + .append($findElement), + size: 24 + }, + { + element: $list + } + ], + orientation: 'vertical' + }) + }, + { + element: Ox.SplitPanel({ elements: [ { element: Ox.Bar({size: 24}) - .append($guestsCheckbox) - .append($findElement), + .append($formLabel) + .append($formButton), size: 24 }, { - element: $list + element: $form } ], orientation: 'vertical' }) - }, - { - element: Ox.SplitPanel({ - elements: [ - { - element: Ox.Bar({size: 24}) - .append($userLabel), - size: 24 - }, - { - element: $user - } - ], - orientation: 'vertical' + .bindEvent({ + resize: setWidth }), - size: 256 - } - ], - orientation: 'horizontal' - }), - height: height, - maximizeButton: true, - minHeight: 256, - minWidth: 512, - padding: 0, - removeOnClose: true, - title: 'Manage Users', - width: width + resizable: true, + resize: [256, 384, 512], + size: 256 + } + ], + orientation: 'horizontal' }), + that = Ox.Dialog({ + buttons: [ + Ox.Button({ + title: 'Export E-Mail Addresses' + }) + .css({margin: '4px 4px 4px 0'}) + .bindEvent({ + click: function() { + pandora.api.findUsers({ + query: {conditions: [], operator: '&'}, + keys: ['email', 'username'], + range: [0, numberOfUsers], + sort: [{key: 'username', operator: '+'}] + }, function(result) { + var $dialog = Ox.Dialog({ + buttons: [ + Ox.Button({ + title: 'Close' + }) + .bindEvent({ + click: function() { + $dialog.close(); + } + }) + ], + content: Ox.Element() + .addClass('OxSelectable') + .css({margin: '16px'}) + .html( + result.data.items.filter(function(item) { + return item.email; + }).map(function(item) { + return item.username + ' <' + item.email + '>'; + }).join(', ') + ), + removeOnClose: true, + title: 'E-Mail Addresses' + }) + .open(); + }); + } + }), + Ox.Button({ + id: 'done', + title: 'Done', + width: 48 + }).bindEvent({ + click: function() { + Ox.Request.clearCache('findUsers'); + that.close(); + } + }) + ], + closeButton: true, + content: $content, + height: dialogHeight, + maximizeButton: true, + minHeight: 256, + minWidth: 512, + padding: 0, + removeOnClose: true, + title: 'Manage Users', + width: dialogWidth + }) + .bindEvent({ + resize: setHeight + }), + $status = $('
') .css({ position: 'absolute', @@ -383,95 +424,366 @@ pandora.ui.usersDialog = function() { }) .appendTo(that.$element.find('.OxButtonsbar')); + function getFormItemById(id) { + var ret; + Ox.forEach(( + $formButton.value() == 'edit' ? $editForm : $mailForm + ).options('items'), function($item) { + if ($item.options('id') == id) { + ret = $item; + return false; + } + }); + return ret; + }; - function renderUserForm(userData) { - var $checkbox; + function getTo() { + return $list.options('selected').map(function(id) { + return $list.value(id); + }).filter(function(user) { + return user.level != 'guest' && ( + $mailForm.values().include == 'users' || user.newsletter + ); + }).map(function(user) { + return user.username; + }); + } + + function renderEditForm() { + var user = $list.value($list.options('selected')[0]); return Ox.Form({ - items: [ - $checkbox = Ox.Checkbox({ - checked: !userData.disabled, - id: 'status', - label: 'Status', - labelWidth: 80, - title: 'Enabled', - width: 240 - }) - .bindEvent({ - change: function(data) { - // fixme: it would be really nice to have "this" here - $checkbox.options({title: userData.checked ? 'Enabled' : 'Disabled'}) - } - }), - Ox.Input({ - id: 'username', - label: 'Username', - labelWidth: 80, - value: userData.username, - width: 240 - }) - .bindEvent({ - submit: function(data) { - - } - }), - Ox.Input({ - id: 'email', - label: 'E-Mail', - labelWidth: 80, - value: userData.email, - width: 240 - }) - .bindEvent({ - submit: function(data) { - - } - }), - Ox.Select({ - id: 'level', - items: userLevels.map(function(level) { - return { - checked: level == userData.level, - id: level, - title: Ox.toTitleCase(level) - }; - }), - label: 'Level', + items: [ + Ox.Checkbox({ + checked: !user.disabled, + id: 'status', + label: 'Status', labelWidth: 80, - width: 240 - }), - /* - Ox.Label({ - title: 'Notes' - }), - */ - Ox.Input({ - height: 120, - id: 'notes', - placeholder: 'Notes', - type: 'textarea', - value: userData.notes, - width: 240 + title: !user.disabled ? 'Enabled' : 'Disabled', + width: formWidth - 16 }) - ], - width: 240 - }) - .css({margin: '8px'}) - .bindEvent({ - change: function(event) { - var data = {id: userData.id}, key, value; - if (event.id == 'status') { - data.disabled = !event.data.checked; - } else if (event.id == 'level') { - data.level = event.data.selected[0].id; - } else { - data[event.id] = event.data.value; - } - $list.value(userData.id, event.id, data[event.id]); - pandora.api.editUser(data, function(result) { - Ox.Request.clearCache('findUsers'); - }); + .bindEvent({ + change: function(data) { + this.options({ + title: this.options('title') == 'Enabled' + ? 'Disabled' : 'Enabled' + }); + } + }), + Ox.Input({ + id: 'username', + label: 'Username', + labelWidth: 80, + value: user.username, + width: formWidth - 16 + }) + .bindEvent({ + submit: function(data) { + + } + }), + Ox.Input({ + id: 'email', + label: 'E-Mail', + labelWidth: 80, + value: user.email, + width: formWidth - 16 + }) + .bindEvent({ + submit: function(data) { + + } + }), + Ox.Select({ + id: 'level', + items: userLevels.map(function(level) { + return { + checked: level == user.level, + id: level, + title: Ox.toTitleCase(level) + }; + }), + label: 'Level', + labelWidth: 80, + width: formWidth - 16 + }), + Ox.Checkbox({ + checked: user.newsletter, + id: 'newsletter', + label: 'Newsletter', + labelWidth: 80, + title: user.newsletter ? 'Subscribed' : 'Unsubscribed', + width: formWidth - 16 + }) + .bindEvent({ + change: function(data) { + this.options({ + title: this.options('title') == 'Subscribed' + ? 'Unsubscribed' : 'Subscribed' + }); + } + }), + Ox.Input({ + height: dialogHeight - 160, + id: 'notes', + placeholder: 'Notes', + type: 'textarea', + value: user.notes, + width: formWidth - 16 + }) + ], + width: 240 + }) + .css({margin: '8px'}) + .bindEvent({ + change: function(event) { + var data = {id: user.id}, key, value; + if (event.id == 'status') { + data.disabled = !event.data.checked; + } else if (event.id == 'level') { + data.level = event.data.selected[0].id; + } else if (event.id == 'newsletter') { + data.newsletter = event.data.checked; + } else { + data[event.id] = event.data.value; } - }); + $list.value(user.id, event.id, data[event.id]); + pandora.api.editUser(data, function(result) { + Ox.Request.clearCache('findUsers'); + }); + } + }); + } + + function renderMailForm() { + return Ox.Form({ + items: [ + Ox.Input({ + disabled: true, + id: 'from', + label: 'From', + labelWidth: 80, + value: pandora.site.site.name + ' <' + pandora.site.site.email.contact + '>', + width: formWidth - 16 + }), + Ox.Input({ + disabled: true, + id: 'to', + label: 'To', + labelWidth: 80, + value: '', + width: formWidth - 16 + }), + Ox.Select({ + id: 'include', + items: [ + {id: 'users', title: 'All users'}, + {id: 'subscribers', title: 'Subscribers only'}, + ], + label: 'Include', + labelWidth: 80, + width: formWidth - 16 + }) + .bindEvent({ + change: function() { + setTo(); + setSend(); + } + }), + Ox.Input({ + id: 'subject', + label: 'Subject', + labelWidth: 80, + value: pandora.site.site.email.prefix + ' ', + width: formWidth - 16 + }) + .bindEvent({ + change: setSend + }), + Ox.Input({ + height: dialogHeight - 208, + id: 'message', + placeholder: 'Message', + type: 'textarea', + value: '\n\n' + pandora.site.site.email.footer, + width: formWidth - 16 + }) + .bindEvent({ + change: setSend + }), + Ox.Select({ + id: 'insert', + items: [ + {id: 'username', title: 'Username'}, + {id: 'email', title: 'E-Mail address'}, + ], + selectable: false, + title: 'Insert...', + width: formWidth - 16 + }) + .bindEvent({ + click: function(data) { + var $input = getFormItemById('message'), + textarea = $input.find('textarea')[0], + value = $input.options('value'); + $input.options({ + value: value.substr(0, textarea.selectionStart) + + '{' + data.id + '}' + + value.substr(textarea.selectionEnd) + }) + .focusInput(textarea.selectionStart + data.id.length + 2); + } + }), + Ox.Checkbox({ + checked: false, + id: 'receipt', + title: 'Send a receipt to ' + pandora.user.email, + width: formWidth - 16 + }), + Ox.Button({ + disabled: true, + id: 'send', + title: 'Send', + width: 64 + }) + .bindEvent({ + click: sendMail + }) + ], + width: formWidth - 16 + }) + .css({margin: '8px', textAlign: 'right'}); + } + + function selectForm(data) { + var selected; + if (data.selected[0] == 'edit') { + $mailForm.detach(); + selected = $list.options('selected'); + if (selected.length == 1 && selected[0].level != 'guest') { + $form.append($editForm = renderEditForm()); + } + } else { + setTo(); + setSend(); + setWidth(); + $editForm && $editForm.remove(); + $form.append($mailForm); + } + } + + function selectUsers(data) { + var users = $list.options('selected').map(function(id) { + return $list.value(id); + }); + setLabel(); + if ($formButton.value() == 'edit') { + $form.empty(); + if (data.ids.length == 1) { + if (users[0].level != 'guest') { + $form.append($editForm = renderEditForm()); + } + } + } else { + setTo(); + setSend(); + } + } + + function sendMail() { + pandora.api.mail({ + to: getTo(), + subject: getFormItemById('subject').options('value'), + message: getFormItemById('message').options('value'), + receipt: getFormItemById('receipt').value() + }, function(result) { + var title = result.status.code == 200 + ? 'Message Sent' + : 'Application Error', + message = result.status.code == 200 + ? 'Your message has been sent.' + : 'Your message could not be sent. Please try again.', + $dialog = Ox.Dialog({ + buttons: [ + Ox.Button({ + id: 'close', + title: 'Close' + }) + .bindEvent({ + click: function() { + $dialog.close(); + } + }) + ], + // FIXME: we need a template for this type of dialog + content: Ox.Element() + .append( + $('') + .attr({src: '/static/png/icon64.png'}) + .css({position: 'absolute', left: '16px', top: '16px', width: '64px', height: '64px'}) + ) + .append( + $('
') + .css({position: 'absolute', left: '96px', top: '16px', width: '192px'}) + .html(message) + ), + height: 128, + keys: {enter: 'close', escape: 'close'}, + removeOnClose: true, + title: title, + width: 304 + }).open(); + }); + } + + function setHeight(data) { + var form = $formButton.options('value'), + $item = getFormItemById(form == 'edit' ? 'notes' : 'message'); + Ox.print('$ITEM', $item) + dialogHeight = data.height; + $item && $item.options({ + height: dialogHeight - (form == 'edit' ? 160 : 208) + }); + } + + function setLabel() { + var users = $list.options('selected').map(function(id) { + return $list.value(id); + }), + title = users.length == 0 ? 'No user selected' + : users.length == 1 ? ( + users[0].level == 'guest' + ? 'Guest' + : users[0].username + ' <' + users[0].email + '>' + ) + : users.length + ' users selected'; + $formLabel.options({title: title}); + } + + function setSend() { + getFormItemById('send').options({ + disabled: getFormItemById('to').options('value') == 'No recipients' + || getFormItemById('subject').options('value') === '' + || getFormItemById('message').options('value') === '' + }); + } + + function setTo() { + var recipients = getTo().length; + $mailForm.values({ + to: (recipients || 'No') + ' recipient' + (recipients == 1 ? '' : 's') + }); + } + + function setWidth() { + formWidth = $content.size(1); + $formLabel.options({width: formWidth - 44}); + ( + $formButton.value() == 'edit' ? $editForm : $mailForm + ).options('items').forEach(function($item) { + if ($item.options('id') != 'send') { + $item.options({width: formWidth - 16}); + } + }); } function updateList() {