blob: d87aee70bec211710e18762acacb65a0a1d98003 [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
import logging
from tg import tmpl_context as c, app_globals as g
from tg import expose, redirect, config
from itertools import islice
from ming.orm import session
from allura.model.timeline import perm_check, get_activity_object
from allura.controllers import BaseController
from allura.controllers.feed import FeedController
from allura.lib.widgets.user_profile import SectionBase, SectionsUtil, ProjectsSectionBase
from allura.lib.widgets import form_fields as ffw
from paste.deploy.converters import asbool
log = logging.getLogger(__name__)
class DashboardController(BaseController, FeedController):
@expose('jinja:allura.ext.personal_dashboard:templates/dashboard_index.html')
def index(self, **kw):
if not c.user.is_anonymous():
user = c.user
sections = [section(user)
for section in SectionsUtil.load_sections('personal_dashboard')]
return dict(user=user, sections=sections, title="Personal Dashboard")
else:
redirect('/neighborhood')
class DashboardSectionBase(SectionBase):
"""
This is the base class for sections on the Dashboard tool.
.. py:attribute:: template
A resource string pointing to the template for this section. E.g.::
template = "allura.ext.personal_dashboard:templates/projects.html"
Sections must be pointed to by an entry-point in the group
``[allura.personal_dashboard.sections]``.
"""
class ProjectsSection(DashboardSectionBase, ProjectsSectionBase):
template = 'allura.ext.personal_dashboard:templates/sections/projects.html'
class TicketsSection(DashboardSectionBase):
template = 'allura.ext.personal_dashboard:templates/sections/tickets.html'
def query_tickets(self, page, limit):
from forgetracker.model import Ticket
q = ' OR '.join(['assigned_to:' + str(self.user['username']), 'reported_by:' + str(self.user['username'])])
sort = 'mod_date_dt desc'
result = Ticket.paged_search(None, self.user, q, limit=limit, page=page, sort=sort)
tickets = [
dict(
ticket_num=ticket['ticket_num'],
url=ticket.url(),
summary=ticket['summary'],
mod_date=ticket['mod_date'],
reported_by=ticket['reported_by'],
assigned_to_id=ticket['assigned_to_id'],
assigned_to=ticket['assigned_to'],
status=ticket['status'])
for ticket in result.get('tickets')
]
return dict(tickets=tickets, count=result.get('count'), solr_error=result.get('solr_error'))
def prepare_context(self, context):
page = 0
limit = 25
page_string = context['c'].form_values.get('page')
limit_string = context['c'].form_values.get('limit')
if page_string is not None:
page = int(page_string)
if limit_string is not None:
limit = int(limit_string)
result = self.query_tickets(page, limit)
context['page_size'] = ffw.PageSize()
context['page_list'] = ffw.PageList()
context['page'] = page
context['limit'] = limit
context['tickets'] = result.get('tickets')
context['count'] = result.get('count')
context['solr_error'] = result.get('solr_error')
return context
class MergeRequestsSection(DashboardSectionBase):
template = 'allura.ext.personal_dashboard:templates/sections/merge_requests.html'
def get_merge_requests(self):
return [
merge_request
for merge_request in self.user.my_merge_requests()]
def prepare_context(self, context):
context['requests'] = self.get_merge_requests()
return context
def __json__(self):
merge_requests = [
dict(
status=merge_request['status'],
summary=merge_request['summary'],
repository=merge_request['repository'],
created=merge_request['created'],
updated=merge_request['updated'])
for merge_request in self.get_merge_requests()]
return dict(merge_requests=merge_requests)
class ActivitySection(DashboardSectionBase):
template = 'allura.ext.personal_dashboard:templates/sections/activity.html'
def __init__(self, user):
super(DashboardSectionBase, self).__init__(user)
self.activity_app = c.user.private_project().app_instance('activity')
def check_display(self):
app_installed = self.activity_app is not None
activity_enabled = asbool(config.get('activitystream.enabled', False))
return app_installed and activity_enabled
def prepare_context(self, context):
full_timeline = g.director.get_timeline(
self.user, page=0, limit=100,
actor_only=False,
)
filtered_timeline = list(islice(filter(perm_check(c.user), full_timeline),
0, 8))
for activity in filtered_timeline:
# Get the project for the activity.obj so we can use it in the
# template. Expunge first so Ming doesn't try to flush the attr
# we create to temporarily store the project.
#
# The get_activity_object() calls are cheap, pulling from
# the session identity map instead of mongo since identical
# calls are made by perm_check() above.
session(activity).expunge(activity)
activity_obj = get_activity_object(activity.obj)
activity.obj.project = getattr(activity_obj, 'project', None)
context['timeline'] = filtered_timeline
context['activity_app'] = self.activity_app
return context