| '''IRC Chatbot Plugin |
| ''' |
| #-*- python -*- |
| import logging |
| from datetime import date, time, datetime, timedelta |
| |
| # Non-stdlib imports |
| import pkg_resources |
| from tg import expose, validate, redirect, flash |
| from tg.decorators import with_trailing_slash |
| from pylons import g, c, request |
| from formencode import validators |
| |
| # Pyforge-specific imports |
| from allura.app import Application, ConfigOption, SitemapEntry, DefaultAdminController |
| from allura.lib import helpers as h |
| from allura.lib.search import search |
| from allura.lib.decorators import require_post |
| from allura.lib.security import require_access |
| from allura import model as M |
| from allura.controllers import BaseController |
| |
| # Local imports |
| from forgechat import model as CM |
| from forgechat import version |
| |
| log = logging.getLogger(__name__) |
| |
| class ForgeChatApp(Application): |
| __version__ = version.__version__ |
| tool_label='Chat' |
| status='alpha' |
| default_mount_label='Chat' |
| default_mount_point='chat' |
| ordinal=13 |
| installable = True |
| permissions = ['configure', 'read' ] |
| config_options = Application.config_options + [ |
| ConfigOption('channel', str, ''), |
| ] |
| icons={ |
| 24:'images/chat_24.png', |
| 32:'images/chat_32.png', |
| 48:'images/chat_48.png' |
| } |
| |
| def __init__(self, project, config): |
| Application.__init__(self, project, config) |
| self.channel = CM.ChatChannel.query.get(app_config_id=config._id) |
| self.root = RootController() |
| self.admin = AdminController(self) |
| |
| @property |
| @h.exceptionless([], log) |
| def sitemap(self): |
| menu_id = self.config.options.mount_label.title() |
| with h.push_config(c, app=self): |
| return [ |
| SitemapEntry(menu_id, '.')[self.sidebar_menu()] ] |
| |
| @h.exceptionless([], log) |
| def sidebar_menu(self): |
| return [ |
| SitemapEntry('Home', '.'), |
| SitemapEntry('Search', 'search'), |
| ] |
| |
| def admin_menu(self): |
| return super(ForgeChatApp, self).admin_menu() |
| |
| def install(self, project): |
| 'Set up any default permissions and roles here' |
| super(ForgeChatApp, self).install(project) |
| role_admin = M.ProjectRole.by_name('Admin')._id |
| role_anon = M.ProjectRole.anonymous()._id |
| self.config.acl = [ |
| M.ACE.allow(role_anon, 'read'), |
| M.ACE.allow(role_admin, 'configure'), |
| ] |
| CM.ChatChannel( |
| project_id=self.config.project_id, |
| app_config_id=self.config._id, |
| channel=self.config.options['channel']) |
| |
| def uninstall(self, project): |
| "Remove all the tool's artifacts from the database" |
| CM.ChatChannel.query.remove(dict( |
| project_id=self.config.project_id, |
| app_config_id=self.config._id)) |
| super(ForgeChatApp, self).uninstall(project) |
| |
| class AdminController(DefaultAdminController): |
| |
| @with_trailing_slash |
| def index(self, **kw): |
| redirect(c.project.url()+'admin/tools') |
| |
| @expose() |
| @require_post() |
| def configure(self, channel=None): |
| with h.push_config(c, app=self.app): |
| require_access(self.app, 'configure') |
| chan = CM.ChatChannel.query.get( |
| project_id=self.app.config.project_id, |
| app_config_id=self.app.config._id) |
| chan.channel = channel |
| flash('Chat options updated') |
| super(AdminController, self).configure(channel=channel) |
| |
| class RootController(BaseController): |
| |
| @expose() |
| def index(self, **kw): |
| now = datetime.utcnow() |
| redirect(c.app.url + now.strftime('%Y/%m/%d/')) |
| |
| @expose('jinja:forgechat:templates/chat/search.html') |
| @validate(dict(q=validators.UnicodeString(if_empty=None), |
| history=validators.StringBool(if_empty=False))) |
| def search(self, q=None, history=None, **kw): |
| 'local tool search' |
| results = [] |
| count=0 |
| if not q: |
| q = '' |
| else: |
| results = search( |
| q, |
| fq=[ |
| 'is_history_b:%s' % history, |
| 'project_id_s:%s' % c.project._id, |
| 'mount_point_s:%s'% c.app.config.options.mount_point ]) |
| if results: count=results.hits |
| return dict(q=q, history=history, results=results or [], count=count) |
| |
| @expose() |
| def _lookup(self, y, m, d, *rest): |
| y,m,d = int(y), int(m), int(d) |
| return DayController(date(y,m,d)), rest |
| |
| class DayController(RootController): |
| |
| def __init__(self, day): |
| self.day = day |
| |
| @expose('jinja:forgechat:templates/chat/day.html') |
| def index(self, **kw): |
| q = dict( |
| timestamp={ |
| '$gte':datetime.combine(self.day, time.min), |
| '$lte':datetime.combine(self.day, time.max)}) |
| messages = CM.ChatMessage.query.find(q).sort('timestamp').all() |
| prev = c.app.url + (self.day - timedelta(days=1)).strftime('%Y/%m/%d/') |
| next = c.app.url + (self.day + timedelta(days=1)).strftime('%Y/%m/%d/') |
| return dict( |
| day=self.day, |
| messages=messages, |
| prev=prev, |
| next=next) |