| 1 | # |
|---|
| 2 | # Copyright 2008 Optaros, Inc |
|---|
| 3 | # |
|---|
| 4 | import random |
|---|
| 5 | import re |
|---|
| 6 | import sys |
|---|
| 7 | import logging |
|---|
| 8 | import traceback |
|---|
| 9 | |
|---|
| 10 | from logging import handlers |
|---|
| 11 | |
|---|
| 12 | import cjson |
|---|
| 13 | |
|---|
| 14 | from django.core.paginator import Paginator |
|---|
| 15 | from django.core.urlresolvers import reverse |
|---|
| 16 | from django.http import HttpResponse, HttpResponseRedirect |
|---|
| 17 | from django.template import Context, RequestContext, loader |
|---|
| 18 | from django.shortcuts import render_to_response |
|---|
| 19 | |
|---|
| 20 | from oforgetools.projects.models import Project, ProjectManager, Ticket, CustomProjectAttributes |
|---|
| 21 | from oforgetools.projects.models import OForgeProfile, OForgeProfileManager |
|---|
| 22 | from oforgetools.projects.forms import CreateProjectForm |
|---|
| 23 | from oforgetools import settings |
|---|
| 24 | from tagging.models import Tag, TaggedItem |
|---|
| 25 | |
|---|
| 26 | from oforge.api import OForge |
|---|
| 27 | |
|---|
| 28 | oforge_logger_initialized = False |
|---|
| 29 | |
|---|
| 30 | def index(request): |
|---|
| 31 | data = {} |
|---|
| 32 | data['my_project_count'] = _get_user_projects_count(request.user) |
|---|
| 33 | data['my_tickets_count'] = _get_user_tickets_count(request.user.username) |
|---|
| 34 | data['featured_projects'] = _get_featured_projects() |
|---|
| 35 | |
|---|
| 36 | return render_to_response('projects/index.html', |
|---|
| 37 | {'data': data}, |
|---|
| 38 | context_instance=RequestContext(request)) |
|---|
| 39 | |
|---|
| 40 | def search(request): |
|---|
| 41 | data = {'types': ProjectManager.reference_data('type'), |
|---|
| 42 | 'phases': CustomProjectAttributes.reference_values('phase'), |
|---|
| 43 | 'regions': CustomProjectAttributes.reference_values('region') } |
|---|
| 44 | data['my_project_count'] = _get_user_projects_count(request.user) |
|---|
| 45 | data['my_tickets_count'] = _get_user_tickets_count(request.user.username) |
|---|
| 46 | |
|---|
| 47 | return render_to_response('projects/search.html', |
|---|
| 48 | {'data': data}, |
|---|
| 49 | context_instance=RequestContext(request)) |
|---|
| 50 | |
|---|
| 51 | def tickets(request): |
|---|
| 52 | data = {} |
|---|
| 53 | ticket_set = _get_tickets(owner=request.user.username) |
|---|
| 54 | data['tickets'] = ticket_set |
|---|
| 55 | data['my_project_count'] = _get_user_projects_count(request.user) |
|---|
| 56 | data['my_tickets_count'] = _get_user_tickets_count(request.user.username) |
|---|
| 57 | return render_to_response('projects/tickets.html', |
|---|
| 58 | {'data': data}, |
|---|
| 59 | context_instance=RequestContext(request)) |
|---|
| 60 | |
|---|
| 61 | def createprojectform(request): |
|---|
| 62 | logging.debug(sys.path) |
|---|
| 63 | data = {'my_project_count': 0} |
|---|
| 64 | if request.method == 'POST': |
|---|
| 65 | form = CreateProjectForm(request.POST) |
|---|
| 66 | data['form'] = form |
|---|
| 67 | if form.is_valid(): |
|---|
| 68 | name = form.cleaned_data['name'] |
|---|
| 69 | client = form.cleaned_data['client'] |
|---|
| 70 | display_name = form.cleaned_data['display_name'] |
|---|
| 71 | admins = form.cleaned_data['admins'] |
|---|
| 72 | type = form.cleaned_data['type'] |
|---|
| 73 | createsvn = form.cleaned_data['createsvn'] |
|---|
| 74 | svn_template = form.cleaned_data['svn_template'] |
|---|
| 75 | default_workspace = form.cleaned_data['default_workspace'] |
|---|
| 76 | usepostgres = form.cleaned_data['use_postgres'] |
|---|
| 77 | versioning_engine = form.cleaned_data['versioning_engine'] |
|---|
| 78 | tags = form.cleaned_data['tags'] |
|---|
| 79 | oforge = OForge(settings.OFORGE_CONFIGFILE) |
|---|
| 80 | try: |
|---|
| 81 | if not oforge_logger_initialized: |
|---|
| 82 | _init_oforge_logger() |
|---|
| 83 | oforge.createproject( |
|---|
| 84 | name, |
|---|
| 85 | display_name=display_name, |
|---|
| 86 | admins=admins, |
|---|
| 87 | type=type, |
|---|
| 88 | createsvn=createsvn, |
|---|
| 89 | svntemplate=svn_template, |
|---|
| 90 | defaultworkspace=default_workspace, |
|---|
| 91 | postgres=usepostgres, |
|---|
| 92 | tags=tags |
|---|
| 93 | ) |
|---|
| 94 | new_proj = Project.objects.filter(name=name)[0] |
|---|
| 95 | new_proj.client = client |
|---|
| 96 | new_proj.save() |
|---|
| 97 | for i in request.POST.items(): |
|---|
| 98 | if i[0].startswith('custom_attribute_'): |
|---|
| 99 | attr_name = i[0].replace('custom_attribute_', '', 1) |
|---|
| 100 | new_proj.set_attribute(attr_name, i[1]) |
|---|
| 101 | flash = "Project <a href='/trac/%s'>%s</a> was created " \ |
|---|
| 102 | "successfully."%(name, display_name) |
|---|
| 103 | request.user.message_set.create(message=flash) |
|---|
| 104 | except Exception, e: |
|---|
| 105 | print >> sys.stderr, traceback.format_exc() |
|---|
| 106 | request.user.message_set.create(message=("Error: %s"%( |
|---|
| 107 | e.message or 'unknown'))) |
|---|
| 108 | request.user.message_set.create( |
|---|
| 109 | message='An error occurred. Please contact the " \ |
|---|
| 110 | "System Administrator.') |
|---|
| 111 | return HttpResponseRedirect( |
|---|
| 112 | reverse('oforgetools.projects.views.createprojectform')) |
|---|
| 113 | else: |
|---|
| 114 | data['my_project_count'] = _get_user_projects_count(request.user) |
|---|
| 115 | data['my_tickets_count'] = _get_user_tickets_count( |
|---|
| 116 | request.user.username) |
|---|
| 117 | defaults = settings.CREATE_PROJECT_DEFAULTS |
|---|
| 118 | data['form'] = CreateProjectForm() |
|---|
| 119 | data['defaults'] = {} |
|---|
| 120 | if defaults.get('svntemplate', None): |
|---|
| 121 | data['defaults']['svn_template'] = defaults.get('svntemplate') |
|---|
| 122 | if defaults.get('defaultworkspace', None): |
|---|
| 123 | data['defaults']['default_workspace'] = \ |
|---|
| 124 | defaults.get('defaultworkspace') |
|---|
| 125 | if defaults.get('usepostgres', True): |
|---|
| 126 | data['defaults']['use_postgres'] = defaults.get('usepostgres', |
|---|
| 127 | True) |
|---|
| 128 | return render_to_response('projects/createproject.html', |
|---|
| 129 | {'data': data}, |
|---|
| 130 | context_instance=RequestContext(request)) |
|---|
| 131 | |
|---|
| 132 | def _init_oforge_logger(): |
|---|
| 133 | logger = logging.getLogger('OForge') |
|---|
| 134 | logger.setLevel(logging.DEBUG) |
|---|
| 135 | slh = handlers.SysLogHandler('/dev/log') |
|---|
| 136 | slh.setLevel(logging.DEBUG) |
|---|
| 137 | formatter = logging.Formatter("[%(name)s]: %(levelname)s: %(message)s") |
|---|
| 138 | slh.setFormatter(formatter) |
|---|
| 139 | logger.addHandler(slh) |
|---|
| 140 | oforge_logger_initialized = True |
|---|
| 141 | |
|---|
| 142 | def autocomplete(request): |
|---|
| 143 | field = request.REQUEST.get('field') |
|---|
| 144 | query = request.REQUEST.get('q') |
|---|
| 145 | default = request.REQUEST.get('default') |
|---|
| 146 | words = [] |
|---|
| 147 | if field == 'client': |
|---|
| 148 | words = Project.objects.filter(client__icontains=query |
|---|
| 149 | ).order_by('client').distinct().values_list( |
|---|
| 150 | 'client', flat=True) |
|---|
| 151 | elif field == 'display_name': |
|---|
| 152 | words = Project.objects.filter(display_name__icontains=query |
|---|
| 153 | ).order_by('display_name').distinct().values_list( |
|---|
| 154 | 'display_name', flat=True) |
|---|
| 155 | elif field == 'tags': |
|---|
| 156 | matching_tags = Tag.objects.filter(name__icontains=query).order_by('name') |
|---|
| 157 | words = [tag.name for tag in matching_tags] |
|---|
| 158 | |
|---|
| 159 | words_list = list(words) |
|---|
| 160 | if default and default <> '' and re.match(query, default, re.IGNORECASE): |
|---|
| 161 | words_list.append(default) |
|---|
| 162 | words_list.sort() |
|---|
| 163 | return HttpResponse(words_list and '\n'.join(words_list) or '') |
|---|
| 164 | |
|---|
| 165 | |
|---|
| 166 | def dashboard_select(request): |
|---|
| 167 | id = request.REQUEST.get('id') |
|---|
| 168 | selected = request.REQUEST.get('selected') == 'true' |
|---|
| 169 | |
|---|
| 170 | try: |
|---|
| 171 | user_profile = OForgeProfileManager().get_user_profile(user=request.user) |
|---|
| 172 | project = Project.objects.get(id=id) |
|---|
| 173 | if selected: |
|---|
| 174 | user_profile.dashboard_projects.add(project) |
|---|
| 175 | else: |
|---|
| 176 | user_profile.dashboard_projects.remove(project) |
|---|
| 177 | user_profile.save() |
|---|
| 178 | except: |
|---|
| 179 | logging.warning("Problem updating user projects: %s", sys.exc_info()[0]) |
|---|
| 180 | |
|---|
| 181 | return HttpResponse(cjson.encode({'my_project_count':user_profile.dashboard_projects.count()})) |
|---|
| 182 | |
|---|
| 183 | def projects_json(request): |
|---|
| 184 | user_projects=[] |
|---|
| 185 | try: |
|---|
| 186 | user_profile = OForgeProfileManager().get_user_profile(user=request.user) |
|---|
| 187 | user_projects = user_profile.dashboard_projects.all() |
|---|
| 188 | except: |
|---|
| 189 | logging.warning("Problem loading user projects: %s", sys.exc_info()[0]) |
|---|
| 190 | |
|---|
| 191 | page = _get_projects_by_request(request) |
|---|
| 192 | data = { |
|---|
| 193 | 'page': page.number, |
|---|
| 194 | 'total': page.paginator.num_pages, |
|---|
| 195 | 'records': page.paginator.count |
|---|
| 196 | } |
|---|
| 197 | |
|---|
| 198 | rows = [] |
|---|
| 199 | for project in page.object_list: |
|---|
| 200 | p = {} |
|---|
| 201 | p['id'] = project.id |
|---|
| 202 | p['url'] = project.url() |
|---|
| 203 | p['type'] = project.type |
|---|
| 204 | p['state'] = project.state |
|---|
| 205 | p['dashboard'] = project in user_projects and 'true' or 'false' |
|---|
| 206 | p['name'] = project.name |
|---|
| 207 | p['client'] = project.client |
|---|
| 208 | p['display_name'] = project.display_name |
|---|
| 209 | p['start_date'] = str(project.start_date.date()) |
|---|
| 210 | p['end_date'] = str(project.end_date or '') |
|---|
| 211 | for attr in project.customprojectattributes_set.values(): |
|---|
| 212 | p['custom_attribute_%s'%(attr['name'])] = attr['value'] or '' |
|---|
| 213 | p['tags'] = ', '.join([tag.name for tag in project.tags]) |
|---|
| 214 | rows.append(p) |
|---|
| 215 | data['rows'] = rows |
|---|
| 216 | return HttpResponse(cjson.encode(data)) |
|---|
| 217 | |
|---|
| 218 | def _get_tickets(page=1, rp=50, sortname='project', sortorder='acs', |
|---|
| 219 | owner=None): |
|---|
| 220 | ticket_set = Ticket.objects.exclude(status='closed') |
|---|
| 221 | if owner: |
|---|
| 222 | ticket_set = ticket_set.filter(owner=owner) |
|---|
| 223 | return ticket_set |
|---|
| 224 | |
|---|
| 225 | def _get_projects(page=1, rp=50, sortname='display_name', sortorder='asc', |
|---|
| 226 | display_name=None, type=None, state=None, client=None, |
|---|
| 227 | tags=None, user=None, dashboard=None, |
|---|
| 228 | start_date_range=None): |
|---|
| 229 | |
|---|
| 230 | project_set = Project.objects |
|---|
| 231 | project_set = project_set.exclude(type='hidden') |
|---|
| 232 | |
|---|
| 233 | if dashboard: |
|---|
| 234 | project_set = OForgeProfileManager().get_user_profile(user=user).dashboard_projects.all() |
|---|
| 235 | else: |
|---|
| 236 | if tags and len(tags): |
|---|
| 237 | # FIXME: appears to still be getting UNION rather than INTERSECTION |
|---|
| 238 | project_set=TaggedItem.objects.get_intersection_by_model(Project, tags) |
|---|
| 239 | if client and client <> '': |
|---|
| 240 | project_set = project_set.filter(client__icontains=client) |
|---|
| 241 | if display_name and display_name <> '': |
|---|
| 242 | project_set = project_set.filter(display_name__icontains=display_name) |
|---|
| 243 | if type and type <> '': |
|---|
| 244 | project_set = project_set.filter(type=type) |
|---|
| 245 | if state and state <> '': |
|---|
| 246 | project_set = project_set.filter(state=state) |
|---|
| 247 | if start_date_range: |
|---|
| 248 | project_set = project_set.filter(start_date__gt=start_date_range[0]).\ |
|---|
| 249 | filter(start_date__lt=start_date_range[1]) |
|---|
| 250 | |
|---|
| 251 | if Project._meta.get_all_field_names().__contains__(sortname): |
|---|
| 252 | order_by = "%s%s"%(sortorder == 'desc' and '-' or '', sortname) |
|---|
| 253 | project_set = project_set.order_by(order_by) |
|---|
| 254 | |
|---|
| 255 | paginator = Paginator(project_set, rp) |
|---|
| 256 | return paginator.page(page) |
|---|
| 257 | |
|---|
| 258 | def _get_projects_by_request(request): |
|---|
| 259 | dashboard = request.REQUEST.get('myprojects', None) |
|---|
| 260 | client = request.REQUEST.get('client', None) |
|---|
| 261 | display_name = request.REQUEST.get('display_name', None) |
|---|
| 262 | type = request.REQUEST.get('type', None) |
|---|
| 263 | state = request.REQUEST.get('state', 'Open') |
|---|
| 264 | if state == 'All': |
|---|
| 265 | state = None |
|---|
| 266 | tags = request.REQUEST.get('tags', None) |
|---|
| 267 | page = request.REQUEST.get('page', 1) |
|---|
| 268 | rp = request.REQUEST.get('rows', 50) |
|---|
| 269 | sortname = request.REQUEST.get('sidx', 'display_name') |
|---|
| 270 | sortorder = request.REQUEST.get('sord', None) |
|---|
| 271 | start_date_range_string = request.REQUEST.get('start_date_range', None) |
|---|
| 272 | start_date_range = None |
|---|
| 273 | if start_date_range_string and start_date_range_string <> '': |
|---|
| 274 | SDRre = '^(\d{2}/\d{2}/\d{4})\s-\s(\d{2}/\d{2}/\d{4})$' |
|---|
| 275 | match = re.match(SDRre, start_date_range_string) |
|---|
| 276 | if match: |
|---|
| 277 | start_date_range = match.groups() |
|---|
| 278 | return _get_projects(page=int(page), rp=int(rp), |
|---|
| 279 | sortname=sortname, sortorder=sortorder, client=client, |
|---|
| 280 | display_name=display_name, type=type, state=state, |
|---|
| 281 | tags=tags, user=request.user, dashboard=dashboard, |
|---|
| 282 | start_date_range=start_date_range) |
|---|
| 283 | |
|---|
| 284 | def _get_user_projects_count(user): |
|---|
| 285 | user_profile = OForgeProfileManager().get_user_profile(user) |
|---|
| 286 | return user_profile.dashboard_projects.count() |
|---|
| 287 | |
|---|
| 288 | def _get_user_tickets_count(username): |
|---|
| 289 | return Ticket.objects.exclude(status='closed').filter(owner=username).count() |
|---|
| 290 | |
|---|
| 291 | def _get_featured_projects(): |
|---|
| 292 | return { |
|---|
| 293 | 'featured':TaggedItem.objects.get_intersection_by_model(Project, 'featured')[:4], |
|---|
| 294 | 'latest': Project.objects.order_by('start_date')[:4], |
|---|
| 295 | 'popular':TaggedItem.objects.get_intersection_by_model(Project, 'popular')[:4], |
|---|
| 296 | 'resource':TaggedItem.objects.get_intersection_by_model(Project, 'resource')[:4], |
|---|
| 297 | } |
|---|