def dispatch(self): client_id = self.request.GET.get('client_id') client = Client.query.get(client_id) form = ProjectForm(self.request.POST) if self.request.method == 'POST' and form.validate(): tracker_id = form.tracker_id.data coordinator_id = int(form.coordinator_id.data) if form.coordinator_id.data.isdigit() else None project = Project( client=client, name=form.name.data, coordinator_id=coordinator_id, tracker_id=tracker_id, turn_off_selectors=form.turn_off_selectors.data, project_selector=form.project_selector.data, component_selector=form.component_selector.data, version_selector=form.version_selector.data, ticket_id_selector=form.ticket_id_selector.data, active=form.active.data, google_card=form.google_card.data, google_wiki=form.google_wiki.data, mailing_url=form.mailing_url.data, working_agreement=form.working_agreement.data, definition_of_done=form.definition_of_done.data, definition_of_ready=form.definition_of_ready.data, continuous_integration_url=form.continuous_integration_url.data, backlog_url=form.backlog_url.data, status = form.status.data, ) DBSession.add(project) DBSession.flush() self.flash(self._(u"Project added")) LOG(u"Project added") SelectorMapping.invalidate_for(tracker_id) return HTTPFound(location=self.request.url_for('/client/view', client_id=project.client_id)) return dict(client=client, form=form)
def get(self): check_role = self.request.GET.get('role') if not check_role or check_role == 'None': pivot_q = DBSession.query(User.id, User.name, User.start_work, User.stop_work, User.roles)\ .filter(User.is_not_client())\ .filter(User.is_active==True)\ .order_by(User.name) else: pivot_q = DBSession.query(User.id, User.name, User.start_work, User.stop_work, User.roles)\ .filter(User.is_not_client())\ .filter(User.is_active==True)\ .filter(User.roles.op('&&')('{%s}'%(check_role)))\ .order_by(User.name) users = {} for s in pivot_q: if s.start_work: users.setdefault(s.start_work.year, [0] * 24)[s.start_work.month - 1] += 1 if s.stop_work: users.setdefault(s.stop_work.year, [0] * 24)[s.stop_work.month - 1 + 12] += 1 role = User.ROLES return dict( start=users, roles=role, check=check_role, quarters_sum=self._quarters_sum, link_with_year=self._create_link_with_year, link_with_month=self._create_link_with_month, link_with_quarter=self._create_link_with_quarter, )
def dispatch(self): form = SprintForm(self.request.POST) if self.request.method == 'POST' and form.validate(): project = Project.query.get(int(form.project_id.data)) sprint = Sprint( name=form.name.data, client_id=project.client_id, project_id=project.id, team_id=form.team_id.data or None, bugs_project_ids = map(int, form.bugs_project_ids.data), start=form.start.data, end=form.end.data, board=form.board.data, goal=form.goal.data, retrospective_note = form.retrospective_note.data, ) DBSession.add(sprint) DBSession.flush() self.flash(self._(u"New sprint added")) LOG(u"Sprint added") url = self.request.url_for('/scrum/sprint/show', sprint_id=sprint.id) return HTTPFound(location=url) return dict( form=form, )
def calculate_velocities(self): self.velocity = \ 8.0 * self.achieved_points / self.worked_hours \ if self.worked_hours else 0.0 self.story_velocity = \ 8.0 * self.achieved_points / self.bugs_worked_hours \ if self.bugs_worked_hours else 0.0 sprint_velocities = DBSession.query( Sprint.velocity, Sprint.story_velocity, ).filter(Sprint.project_id == self.project_id) \ .filter(Sprint.id != self.id) \ .all() sprint_velocities.append((self.velocity, self.story_velocity)) velocities, story_velocities = zip(*sprint_velocities) self.velocity_mean = float(sum(velocities)) / len(velocities) self.story_velocity_mean = \ float(sum(story_velocities)) / len(story_velocities) DBSession.add(self)
class UserChoices(object): def __init__(self, empty=False, inactive=False): self.empty = empty self.inactive = inactive self.session = DBSession() def __iter__(self): if self.empty: yield "", u"-- None --" query = ( self.session.query(User.id, User.name) .filter(not_(User.is_client())) .filter(User.is_active == True) .order_by(User.name) ) for id, name in query: yield str(id), name if self.inactive: yield "", " " * 8 query = ( self.session.query(User.id, User.name) .filter(User.is_client()) .filter(User.is_active == False) .order_by(User.name) ) for id, name in query: yield str(id), name
def __init__(self, event): today = datetime.date.today() user = event['request'].user self.arrival = None if not user: return row = DBSession.query('ts').from_statement(""" SELECT MIN(p.ts) as "ts" FROM presence_entry p WHERE DATE(p.ts) = :today AND p.user_id = :user_id """).params(today=today, user_id=user.id).first() if not (row and row.ts): return arrival = row.ts now = datetime.datetime.now() since_morning_hours = float((now - arrival).seconds) / 3600 self.present = since_morning_hours noted = 0.0 row = DBSession.query('time').from_statement(""" SELECT COALESCE(SUM(t.time), 0.0) as "time" FROM time_entry t WHERE t.date = :today AND t.user_id = :user_id AND t.deleted = FALSE """).params(user_id=user.id, today=today).first() if row: noted = row.time self.noted = noted self.remaining = since_morning_hours - noted self.arrival = arrival
def tmpl_ctx(self): sprint = self.v.get("sprint") if not sprint: sprint_id = self.request.GET.get("sprint_id") sprint = Sprint.query.get(sprint_id) project = Project.query.get(sprint.project_id) sprints = ( DBSession.query(Sprint.project_id, Sprint.worked_hours, Sprint.bugs_worked_hours, Sprint.achieved_points) .filter(Sprint.project_id == sprint.project_id) .all() ) sprint.calculate_velocities(sprints) self.v["project"] = project self.v["sprint"] = sprint prev_sprint = ( DBSession.query(Sprint) .filter(Sprint.project_id == sprint.project_id) .filter(Sprint.start < sprint.start) .order_by(Sprint.start.desc()) .first() ) next_sprint = ( DBSession.query(Sprint) .filter(Sprint.project_id == sprint.project_id) .filter(Sprint.start > sprint.start) .order_by(Sprint.start.asc()) .first() ) return dict(project=project, sprint=sprint, prev_sprint=prev_sprint, next_sprint=next_sprint)
def post(self): tracker_id = self.request.GET.get('tracker_id') tracker = Tracker.query.get(tracker_id) credentials = self._get_current_users_credentials_for_tracker(tracker) form = TrackerLoginForm(self.request.POST, obj=credentials) _add_tracker_login_validator(tracker.name, form) if form.validate(): if credentials is None: credentials = TrackerCredentials( user_id=self.request.user.id, tracker_id=tracker.id, login=form.login.data, password=form.password.data, ) DBSession.add(credentials) else: credentials.login = form.login.data credentials.password = form.password.data self.flash(self._(u"Credentials saved")) LOG(u"Credentials saved") url = self.request.url_for('/tracker/list') return HTTPFound(location=url) return dict(form=form, tracker=tracker)
def post(self): args = self.request.json year = int(args.pop('year')) if 1999 > year > 2099: return dict(status='nok', reason='Zły rok %s' % year) leaves = Leave.query.filter(Leave.year==year).all() leaves = groupby(leaves, lambda l: l.user_id) for user_id, (mandated, remarks) in args.iteritems(): user_id = int(user_id) try: mandated = int(mandated) except Exception: user = User.query.get(user_id) return dict( status='nok', reason=self._(u'Wrong hours format: ${hours} for user ${name}', hours=mandated, name=user.name) ) if 0 > mandated or mandated > 99: user = User.query.get(user_id) return dict( status='nok', reason=self._(u'Wrong hours number: ${hours} for user ${name}', hours=mandated, name=user.name) ) leave_obj = leaves.get(user_id) if not leave_obj: leave_obj = Leave(user_id=user_id, year=year) else: leave_obj = leave_obj[0] leave_obj.number = mandated leave_obj.remarks = remarks DBSession.add(leave_obj) return dict(status='ok')
def get(self): check_role = self.request.GET.get('role') if not check_role or check_role == 'None': pivot_q = DBSession.query(User.id, User.name, User.start_work, User.stop_work, User.roles)\ .filter(User.is_not_client())\ .filter(User.is_active==True)\ .order_by(User.name) else: pivot_q = DBSession.query(User.id, User.name, User.start_work, User.stop_work, User.roles)\ .filter(User.is_not_client())\ .filter(User.is_active==True)\ .filter(User.roles.op('&&')('{%s}'%(check_role)))\ .order_by(User.name) users = {} for s in pivot_q: if s.start_work: users.setdefault(s.start_work.year, [0]*24)[s.start_work.month-1] += 1 if s.stop_work: users.setdefault(s.stop_work.year, [0]*24)[s.stop_work.month-1+12] += 1 role = User.ROLES return dict( start=users, roles=role, check=check_role, quarters_sum=self._quarters_sum, link_with_year=self._create_link_with_year, link_with_month=self._create_link_with_month, link_with_quarter=self._create_link_with_quarter, )
def make_admin(config_path): from intranet3.models import DBSession, Base from intranet3.models import User user_login = sys.argv[-1] if len(sys.argv) < 4: print u"Provide user login" return session = DBSession() user = session.query(User).filter(User.email==user_login).first() if not user: print u"No such user: %s" % user_login return if 'admin' in user.groups: print u'Removing %s from group admin' % user.name groups = list(user.groups) groups.remove('admin') user.groups = groups else: print u'Adding %s to group admin' % user.name groups = list(user.groups) groups.append('admin') user.groups = groups session.add(user) transaction.commit()
def dispatch(self): form = AbsenceCreateForm(self.request.POST, request=self.request) days, mandated, used, left = 0, 0, 0, 0 if form.popup_date_start.data: mandated, used, left = user_leave(self.request, form.popup_date_start.data.year) if form.popup_date_end.data: days = h.get_working_days(form.popup_date_start.data, form.popup_date_end.data) left -= days if self.request.method == 'POST' and form.validate(): date_start = form.popup_date_start.data date_end = form.popup_date_end.data type = form.popup_type.data remarks = form.popup_remarks.data user_id = form.popup_user_id.data absence = Absence( user_id=user_id, date_start=date_start, date_end=date_end, days=days, type=type, remarks=remarks, ) DBSession.add(absence) return Response(self._('Done') + RELOAD_PAGE) return dict(form=form, days=days, mandated=mandated, used=used, left=left)
def add_time(user_id, date, bug_id, project_id, hours, subject): # try finding existing entry for this bug session = DBSession() bug_id = str(bug_id) entry = TimeEntry.query.filter(TimeEntry.user_id==user_id) \ .filter(TimeEntry.date==date.date()) \ .filter(TimeEntry.ticket_id==bug_id) \ .filter(TimeEntry.project_id==project_id).first() if not entry: # create new entry entry = TimeEntry( user_id=user_id, date=date.date(), time=hours, description=subject, ticket_id=bug_id, project_id = project_id, modified_ts=date ) session.add(entry) LOG(u'Adding new entry') else: # update existing entry if not entry.frozen: entry.time += hours entry.modified_ts = date # TODO: this might remove an already existing lateness session.add(entry) LOG(u'Updating existing entry') else: LOG(u'Omission of an existing entry because it is frozen')
def tmpl_ctx(self): sprint = self.v.get('sprint') if not sprint: sprint_id = self.request.GET.get('sprint_id') sprint = Sprint.query.get(sprint_id) project = Project.query.get(sprint.project_id) sprint.calculate_velocities() self.v['project'] = project self.v['sprint'] = sprint prev_sprint = DBSession.query(Sprint)\ .filter(Sprint.project_id == sprint.project_id)\ .filter(Sprint.start < sprint.start)\ .order_by(Sprint.start.desc()).first() next_sprint = DBSession.query(Sprint) \ .filter(Sprint.project_id == sprint.project_id) \ .filter(Sprint.start > sprint.start) \ .order_by(Sprint.start.asc()).first() return dict( project=project, sprint=sprint, prev_sprint=prev_sprint, next_sprint=next_sprint, )
def post(self): tracker_id = self.request.GET.get('tracker_id') tracker = Tracker.query.get(tracker_id) credentials = self._get_current_users_credentials_for_tracker(tracker) form = TrackerLoginForm(self.request.POST, obj=credentials) _add_tracker_login_validator(tracker.name, form) if form.validate(): if credentials is None: credentials = TrackerCredentials( user_id=self.request.user.id, tracker_id=tracker.id, login=form.login.data, password=form.password.data, ) DBSession.add(credentials) else: credentials.login=form.login.data credentials.password=form.password.data self.flash(self._(u"Credentials saved")) LOG(u"Credentials saved") url = self.request.url_for('/tracker/list') return HTTPFound(location=url) return dict(form=form, tracker=tracker)
def dispatch(self): subpage = self.request.GET.get('subpage', 'general') if subpage not in ['general', 'reports', 'spreadsheets', 'access']: return HTTPForbidden() config_obj = ApplicationConfig.get_current_config(allow_empty=True) FormRef = getattr(config_forms, "%sForm" % subpage.title()) if config_obj is not None: LOG(u"Found config object from %s" % (config_obj.date, )) form = FormRef(self.request.POST, obj=config_obj) else: LOG(u"Config object not found") form = FormRef(self.request.POST) if self.request.method == 'POST' and form.validate(): if config_obj is None: config_obj = ApplicationConfig() # Add/Edit data if subpage == 'general': config_obj.office_ip = form.office_ip.data config_obj.google_user_email = form.google_user_email.data config_obj.google_user_password = form.google_user_password.data config_obj.cleaning_time_presence = form.cleaning_time_presence.data config_obj.absence_project_id = form.absence_project_id.data if form.absence_project_id.data else None config_obj.monthly_late_limit = form.monthly_late_limit.data config_obj.monthly_incorrect_time_record_limit = form.monthly_incorrect_time_record_limit.data elif subpage == 'reports': config_obj.reports_project_ids = [ int(id) for id in form.reports_project_ids.data ] config_obj.reports_omit_user_ids = [ int(id) for id in form.reports_omit_user_ids.data ] config_obj.reports_without_ticket_project_ids = [ int(id) for id in form.reports_without_ticket_project_ids.data ] config_obj.reports_without_ticket_omit_user_ids = [ int(id) for id in form.reports_without_ticket_omit_user_ids.data ] elif subpage == 'spreadsheets': config_obj.holidays_spreadsheet = form.holidays_spreadsheet.data config_obj.hours_employee_project = form.hours_employee_project.data config_obj.hours_ticket_user_id = form.hours_ticket_user_id.data if form.hours_ticket_user_id.data else None elif subpage == "access": config_obj.freelancers = form.freelancers.data DBSession.add(config_obj) config_obj.invalidate_office_ip() LOG(u"Config object saved") self.flash(self._(u'Application Config saved'), klass='success') return HTTPFound( location=self.request.url_for('/config/view', subpage=subpage)) return dict(form=form, subpage=subpage)
def make_admin(config_path): from intranet3.models import DBSession, Base from intranet3.models import User user_login = sys.argv[-1] if len(sys.argv) < 4: print u"Provide user login" return session = DBSession() user = session.query(User).filter(User.email == user_login).first() if not user: print u"No such user: %s" % user_login return if 'admin' in user.groups: print u'Removing %s from group admin' % user.name groups = list(user.groups) groups.remove('admin') user.groups = groups else: print u'Adding %s to group admin' % user.name groups = list(user.groups) groups.append('admin') user.groups = groups session.add(user) transaction.commit()
def post(self): if not self.request.is_xhr: return HTTPBadRequest() date = self.v['date'] form = TimeEntryForm(self.request.POST) if form.validate(): project_id = form.project_id.data time = TimeEntry(date=date, user_id=self.request.user.id, time=form.time.data, description=form.description.data, ticket_id=form.ticket_id.data, project_id=project_id if project_id else None) DBSession.add(time) LOG(u'Ajax - Time entry added') entries = self._get_time_entries(date) total_sum = sum(entry.time for (tracker, entry) in entries if not entry.deleted) template = render('/times/_list.html', dict(entries=entries, total_sum=total_sum), request=self.request) return dict(status='success', html=template) errors = u'<br />'.join((u"%s - %s" % (field, u', '.join(errors)) for field, errors in form.errors.iteritems())) return dict(status='error', errors=errors)
def post(self): lateness = self.request.json.get('lateness') form = LateApplicationForm(MultiDict(**lateness), user=self.request.user) if form.validate(): date = form.popup_date.data explanation = form.popup_explanation.data in_future = date > datetime.date.today() late = Late( user_id=self.request.user.id, date=date, explanation=explanation, justified=in_future or None, late_start=form.late_start.data, late_end=form.late_end.data, work_from_home=form.work_from_home.data, ) DBSession.add(late) memcache.delete(MEMCACHED_NOTIFY_KEY % date) if in_future and is_production: event_id = self._add_event(date, explanation) return dict( entry=True ) self.request.response.status = 400 return form.errors
def migrate(config_path): from intranet3.models import DBSession, Sprint, SprintBoard import json def migrate_object(obj): board_json = obj.board if not board_json: return board = json.loads(board_json) if not isinstance(board, list): return board = { "board": board, "colors": [], } obj.board = json.dumps(board) for sprint_board in DBSession.query(SprintBoard): migrate_object(sprint_board) for sprint in DBSession.query(Sprint): migrate_object(sprint) transaction.commit()
def dispatch(self): form = AbsenceCreateForm(self.request.POST, request=self.request) days, mandated, used, left = 0, 0, 0, 0 if form.popup_date_start.data: mandated, used, left = user_leave(self.request, form.popup_date_start.data.year) if form.popup_date_end.data: days = h.get_working_days(form.popup_date_start.data, form.popup_date_end.data) left -= days if self.request.method == 'POST' and form.validate(): date_start = form.popup_date_start.data date_end = form.popup_date_end.data type = form.popup_type.data remarks = form.popup_remarks.data user_id = form.popup_user_id.data absence = Absence( user_id=user_id, date_start=date_start, date_end=date_end, days=days, type=type, remarks=remarks, ) DBSession.add(absence) return Response(self._('Done') + RELOAD_PAGE) return dict( form=form, days=days, mandated=mandated, used=used, left=left )
def dispatch(self): client_id = self.request.GET.get('client_id') client = Client.query.get(client_id) form = ClientForm(self.request.POST, obj=client) if self.request.method == 'POST' and form.validate(): coordinator_id = int(form.coordinator_id.data) if form.coordinator_id.data.isdigit() else None client.name = form.name.data client.active = client.active client.google_card = form.google_card.data client.google_wiki = form.google_wiki.data client.color=form.color.data client.selector = form.selector.data client.emails = form.emails.data client.coordinator_id = coordinator_id client.street = form.street.data client.city = form.city.data client.postcode = form.postcode.data client.nip = form.nip.data client.note = form.note.data client.wiki_url = form.wiki_url.data client.mailing_url = form.mailing_url.data DBSession.add(client) self.flash(self._(u"Client saved")) LOG(u"Client saved") return HTTPFound(location=self.request.url_for("/client/view", client_id=client.id)) projects = client.projects return dict(client_id=client.id, form=form, projects=projects)
def dispatch(self): form = ClientAddForm(self.request.POST) if self.request.method == 'POST' and form.validate(): coordinator_id = int(form.coordinator_id.data) if form.coordinator_id.data.isdigit() else None client = Client( name=form.name.data, google_card=form.google_card.data, google_wiki=form.google_wiki.data, color=form.color.data, selector=form.selector.data, emails=form.emails.data, coordinator_id=coordinator_id, street=form.street.data, city=form.city.data, postcode=form.postcode.data, nip=form.nip.data, note=form.note.data, wiki_url=form.wiki_url.data, mailing_url=form.mailing_url.data ) DBSession.add(client) DBSession.flush() self.flash(self._(u"New client added")) LOG(u"Client added") return HTTPFound(location=self.request.url_for("/client/view", client_id=client.id)) return dict(form=form)
def post(self): lateness = self.request.json.get('lateness') form = LateApplicationForm(MultiDict(**lateness), user=self.request.user) if form.validate(): date = form.popup_date.data explanation = form.popup_explanation.data in_future = date > datetime.date.today() late = Late( user_id=self.request.user.id, date=date, explanation=explanation, justified=in_future or None, late_start=form.late_start.data, late_end=form.late_end.data, work_from_home=form.work_from_home.data, ) DBSession.add(late) memcache.delete(MEMCACHED_NOTIFY_KEY % date) if in_future and is_production: event_id = self._add_event(date, explanation) return dict(entry=True) self.request.response.status = 400 return form.errors
def post(self): if not self.request.is_xhr: return HTTPBadRequest() date = self.v['date'] form = TimeEntryForm(self.request.POST) if form.validate(): project_id = form.project_id.data time = TimeEntry( date = date, user_id = self.request.user.id, time = form.time.data, description = form.description.data, ticket_id = form.ticket_id.data, project_id = project_id if project_id else None ) DBSession.add(time) LOG(u'Ajax - Time entry added') entries = self._get_time_entries(date) total_sum = sum(entry.time for (tracker, entry) in entries if not entry.deleted) template = render( '/times/_list.html', dict(entries=entries, total_sum=total_sum), request=self.request ) return dict(status='success', html=template) errors = u'<br />'.join((u"%s - %s" % (field, u', '.join(errors)) for field, errors in form.errors.iteritems())) return dict(status='error', errors=errors)
def dispatch(self): sprint_id = self.request.GET.get('sprint_id') sprint = Sprint.query.get(sprint_id) form = SprintForm(self.request.POST, obj=sprint) if self.request.method == 'POST' and form.validate(): project_id = form.project_id.data project = Project.query.get(project_id) sprint.name = form.name.data sprint.client_id = project.client_id sprint.project_id = project.id sprint.team_id = form.team_id.data or None sprint.bugs_project_ids = map(int, form.bugs_project_ids.data) sprint.start = form.start.data sprint.end = form.end.data sprint.goal = form.goal.data sprint.board = form.board.data sprint.retrospective_note = form.retrospective_note.data DBSession.add(sprint) self.flash(self._(u"Sprint edited")) LOG(u"Sprint edited") if self.request.POST.get('save-and-go'): url = self.request.url_for('/scrum/sprint/board', sprint_id=sprint.id) else: url = self.request.url_for('/scrum/sprint/edit', sprint_id=sprint.id) return HTTPFound(location=url) return dict( form=form, sprint=sprint )
def init_db(config_path): from intranet3.models import DBSession, Base setup_logging(config_path) settings = get_appsettings(config_path) engine = engine_from_config(settings, 'sqlalchemy.') DBSession.configure(bind=engine) Base.metadata.create_all(engine) print 'Done'
def add_time(cls, orig_bugs, sprint=None): """ @param orig_bugs: list of bugs Add times to bugs, can be used inside and outside the class. """ bugs = dict(((bug.id, bug.project_id), bug) for bug in orig_bugs if bug.project) where_condition = '(t.ticket_id = :bug_id_%s AND t.project_id = :project_id_%s)' conditions = [] params = {} i = 1 for bug in orig_bugs: bug.time = 0.0 bug.sprint_time = 0.0 for bug_id, project_id in bugs: conditions.append(where_condition % (i, i)) params['bug_id_%s' % i] = bug_id params['project_id_%s' % i] = project_id i += 1 if not conditions: return orig_bugs # short circuit to avoid useless (and incorrect) SQL query condition = ' OR '.join(conditions) sql = """ SELECT t.ticket_id as "ticket_id", t.project_id as "project_id", SUM(t.time) as "time" FROM time_entry t WHERE t.deleted = FALSE AND (%s) GROUP BY t.ticket_id, t.project_id """ % (condition, ) query = DBSession.query('ticket_id', 'project_id', 'time').from_statement(sql).params(**params) for bug_id, project_id, time in query: bug = bugs[(bug_id, project_id)] bug.time = time points = bug.scrum.points or 0.0 velocity = ((points / time) * 8.0) if time else 0.0 bug.scrum.velocity = velocity if sprint: params['sprint_start'] = sprint.start params['sprint_end'] = sprint.end sql = """ SELECT t.ticket_id as "ticket_id", t.project_id as "project_id", SUM(t.time) as "time" FROM time_entry t WHERE t.deleted = FALSE AND (%s) AND t.date >= :sprint_start AND t.date <= :sprint_end GROUP BY t.ticket_id, t.project_id """ % (condition, ) query = DBSession.query('ticket_id', 'project_id', 'time').from_statement(sql).params(**params) for bug in orig_bugs: bug.sprint_time = 0.0 for bug_id, project_id, time in query: bugs[(bug_id, project_id)].sprint_time = time return orig_bugs
def get(self): today = datetime.date.today() year = self.request.GET.get('year', today.year) year = int(year) year_start = datetime.date(year, 1, 1) year_end = datetime.date(year, 12, 31) if year == today.year: # if this is current year we calculate hours only to yesterday year_end = today-oneday pivot_q = DBSession.query('id', 'name', 'color', 'date', 'time').from_statement(""" SELECT c.id as id, c.name as name, c.color as color, date_trunc('month', t.date) as date, SUM(t.time) as time FROM time_entry t, project p, client c WHERE t.project_id = p.id AND p.client_id = c.id AND t.date >= :year_start AND t.date <= :year_end AND t.deleted = false GROUP BY c.id, c.name, c.color, date_trunc('month', t.date) """).params(year_start=year_start, year_end=year_end) pivot = {} for p in pivot_q: pivot.setdefault((p.id, p.name, p.color), [0]*12)[p.date.month-1] = int(round(p.time)) pivot = sorted(pivot.iteritems(), key=lambda p: p[0][1]) stats_q = DBSession.query('date', 'time').from_statement(""" SELECT date_trunc('month', t.date) as date, SUM(t.time) as time FROM time_entry t WHERE t.deleted = false GROUP BY date_trunc('month', t.date) """) stats = {} for s in stats_q: stats.setdefault(s.date.year, [0]*12)[s.date.month-1] = int(round(s.time)) # estymation of expected worked hours for current month: month_approx = None if year == today.year and today.day > 1: month_start = datetime.date(today.year, today.month, 1) day_of_week, days_in_month = calendar.monthrange(today.year, today.month) month_end = datetime.date(today.year, today.month, days_in_month) days_worked, days_left = self._get_month_days(month_start, month_end) if not days_worked: days_worked = 1 month_approx = (days_left + days_worked) / days_worked return dict( today=today, year_start=year_start, pivot=pivot, stats=stats, quarters_sum=self._quarters_sum, month_approx=month_approx, )
def get(self): date = self.request.GET.get('date') if date: date = datetime.datetime.strptime(date, '%d.%m.%Y').date() else: date = datetime.date.today() current_data_late = memcache.get(MEMCACHED_NOTIFY_KEY % date) blacklist = self.request.user.notify_blacklist if current_data_late is not None: current_data_late['blacklist'] = blacklist return current_data_late late_query = DBSession.query(User.id, User.name, Late.id, Late.late_start, Late.late_end, Late.explanation, Late.work_from_home) late_query = late_query.filter(User.id == Late.user_id)\ .filter(Late.date == date)\ .filter(Late.deleted == False)\ .order_by(User.name) absences = DBSession.query(User.id, User.name, Absence.id, Absence.date_start, Absence.date_end, Absence.remarks) absences = absences.filter(User.id == Absence.user_id)\ .filter(Absence.deleted == False)\ .filter(Absence.date_start <= date)\ .filter(Absence.date_end >= date)\ .order_by(User.name) current_data_late = dict( lates=[ dict(id=user_id, name=user_name, late_id=late_id, start=start and start.isoformat()[:5] or None, end=end and end.isoformat()[:5] or None, explanation=explanation, work_from_home=work_from_home) for user_id, user_name, late_id, start, end, explanation, work_from_home in late_query ], absences=[ dict(id=user_id, name=user_name, absence_id=absence_id, start=date_start and date_start.strftime('%d.%m.%y') or None, end=date_end and date_end.strftime('%d.%m.%y') or None, remarks=remarks) for user_id, user_name, absence_id, date_start, date_end, remarks in absences ]) memcache.add( MEMCACHED_NOTIFY_KEY % date, current_data_late, 60 * 60 * 24, ) current_data_late['blacklist'] = blacklist return current_data_late
def delete(self): team_id = self.request.matchdict.get('team_id') team = Team_m.query.get(team_id) if not team: raise HTTPNotFound() TeamMember.query.filter(TeamMember.team_id==team.id).delete(synchronize_session=False) DBSession.delete(team) return HTTPOk('OK')
def __call__(self, *args, **kwargs): config = ApplicationConfig.get_current_config(allow_empty=True) if config is None: WARN(u'Application config not found, emails cannot be checked') return trackers = dict( (tracker.mailer, tracker) for tracker in Tracker.query.filter(Tracker.mailer != None).filter(Tracker.mailer != '') ) if not len(trackers): WARN(u'No trackers have mailers configured, email will not be checked') return username = config.google_user_email.encode('utf-8') password = config.google_user_password.encode('utf-8') # TODO logins_mappings = dict( (tracker.id, TrackerCredentials.get_logins_mapping(tracker)) for tracker in trackers.itervalues() ) selector_mappings = dict( (tracker.id, SelectorMapping(tracker)) for tracker in trackers.itervalues() ) # find all projects connected to the tracker projects = dict( (project.id, project) for project in Project.query.all() ) # all pre-conditions should be checked by now # start fetching fetcher = MailFetcher( username, password, ) # ok, we have all mails, lets create timeentries from them extractor = TimeEntryMailExtractor( trackers, logins_mappings, projects, selector_mappings, ) for msg in fetcher: timeentry = extractor.get(msg) if timeentry: DBSession.add(timeentry) transaction.commit()
def dispatch(self): form = ClientTimeForm(self.request.POST) if not (self.request.method == 'POST' and form.validate()): return dict(form=form) date = form.date.data month_start, month_end = self._get_start_end_of_month(date) clients = form.clients.data groupby = form.groupby.data q = DBSession.query(Client.name, Project.name, func.sum(TimeEntry.time))\ .filter(TimeEntry.project_id==Project.id)\ .filter(Project.client_id==Client.id)\ .filter(Client.id.in_(clients))\ .filter(TimeEntry.date >= month_start)\ .filter(TimeEntry.date <= month_end)\ .filter(TimeEntry.deleted==False)\ .group_by(Client.name, Project.name) data = q.all() whole_sum = sum([row[2] for row in data]) whole_sum_without_us = sum( [row[2] for row in data if row[0] != config['COMPANY_NAME']]) q = DBSession.query(func.sum(TimeEntry.time))\ .filter(TimeEntry.project_id==Project.id)\ .filter(Project.client_id==Client.id)\ .filter(Client.id != 12)\ .filter(TimeEntry.date >= month_start)\ .filter(TimeEntry.date <= month_end)\ .filter(TimeEntry.deleted==False) our_monthly_hours = q.one()[0] if groupby == 'client': results = {} for client, project, time in data: results.setdefault(client, 0) results[client] += time results = results.items() data = results data.sort(key=itemgetter(0)) # client else: data.sort(key=itemgetter(0, 1)) # client,project return dict( form=form, groupby=groupby, data=data, whole_sum=whole_sum, whole_sum_without_us=whole_sum_without_us, our_monthly_hours=our_monthly_hours, )
def dispatch(self): form = ClientTimeForm(self.request.POST) if not (self.request.method == 'POST' and form.validate()): return dict(form=form) date = form.date.data month_start, month_end = self._get_start_end_of_month(date) clients = form.clients.data groupby = form.groupby.data q = DBSession.query(Client.name, Project.name, func.sum(TimeEntry.time))\ .filter(TimeEntry.project_id==Project.id)\ .filter(Project.client_id==Client.id)\ .filter(Client.id.in_(clients))\ .filter(TimeEntry.date >= month_start)\ .filter(TimeEntry.date <= month_end)\ .filter(TimeEntry.deleted==False)\ .group_by(Client.name, Project.name) data = q.all() whole_sum = sum([row[2] for row in data]) whole_sum_without_us = sum([row[2] for row in data if row[0] != config['COMPANY_NAME']]) q = DBSession.query(func.sum(TimeEntry.time))\ .filter(TimeEntry.project_id==Project.id)\ .filter(Project.client_id==Client.id)\ .filter(Client.id != 12)\ .filter(TimeEntry.date >= month_start)\ .filter(TimeEntry.date <= month_end)\ .filter(TimeEntry.deleted==False) our_monthly_hours = q.one()[0] if groupby == 'client': results = {} for client, project, time in data: results.setdefault(client, 0) results[client] += time results = results.items() data = results data.sort(key=itemgetter(0)) # client else: data.sort(key=itemgetter(0,1)) # client,project return dict( form=form, groupby=groupby, data=data, whole_sum=whole_sum, whole_sum_without_us=whole_sum_without_us, our_monthly_hours=our_monthly_hours, )
def __iter__(self): if self.empty: yield '', u'-- None --' query = DBSession.query(User.id, User.name).filter(User.is_not_client()).filter(User.is_active==True).order_by(User.name) for id, name in query: yield str(id), name if self.inactive: yield '', ' '*8 query = DBSession.query(User.id, User.name).filter(User.is_not_client()).filter(User.is_active==False).order_by(User.name) for id, name in query: yield str(id), name
def create_config(env): from intranet3.models import * import transaction config = ApplicationConfig( office_ip='', google_user_email='', google_user_password='', holidays_spreadsheet='', hours_employee_project='', ) DBSession.add(config) transaction.commit()
def dispatch(self): subpage = self.request.GET.get('subpage', 'general') if subpage not in ['general', 'reports', 'spreadsheets', 'access']: return HTTPForbidden() config_obj = ApplicationConfig.get_current_config(allow_empty=True) FormRef = getattr(config_forms, "%sForm"% subpage.title()) if config_obj is not None: LOG(u"Found config object from %s" % (config_obj.date, )) form = FormRef(self.request.POST, obj=config_obj) else: LOG(u"Config object not found") form = FormRef(self.request.POST) if self.request.method == 'POST' and form.validate(): if config_obj is None: config_obj = ApplicationConfig() # Add/Edit data if subpage == 'general': config_obj.office_ip = form.office_ip.data config_obj.google_user_email = form.google_user_email.data config_obj.google_user_password = form.google_user_password.data config_obj.cleaning_time_presence = form.cleaning_time_presence.data config_obj.absence_project_id = form.absence_project_id.data if form.absence_project_id.data else None config_obj.monthly_late_limit = form.monthly_late_limit.data config_obj.monthly_incorrect_time_record_limit = form.monthly_incorrect_time_record_limit.data elif subpage == 'reports': config_obj.reports_project_ids = [int(id) for id in form.reports_project_ids.data] config_obj.reports_omit_user_ids = [int(id) for id in form.reports_omit_user_ids.data] config_obj.reports_without_ticket_project_ids = [int(id) for id in form.reports_without_ticket_project_ids.data] config_obj.reports_without_ticket_omit_user_ids = [int(id) for id in form.reports_without_ticket_omit_user_ids.data] elif subpage == 'spreadsheets': config_obj.holidays_spreadsheet = form.holidays_spreadsheet.data config_obj.hours_employee_project = form.hours_employee_project.data config_obj.hours_ticket_user_id = form.hours_ticket_user_id.data if form.hours_ticket_user_id.data else None elif subpage == "access": config_obj.freelancers = form.freelancers.data DBSession.add(config_obj) config_obj.invalidate_office_ip() LOG(u"Config object saved") self.flash(self._(u'Application Config saved'), klass='success') return HTTPFound(location=self.request.url_for('/config/view', subpage=subpage)) return dict( form=form, subpage=subpage )
def post(self): form = TrackerForm(self.request.POST) if form.validate(): tracker = Tracker(type=form.type.data, name=form.name.data, url=form.url.data, mailer=form.mailer.data) DBSession.add(tracker) self.flash(self._(u"New tracker added")) LOG(u"Tracker added") url = self.request.url_for('/tracker/list') return HTTPFound(location=url) return dict(form=form)
def post(self): form = WrongTimeJustificationForm(self.request.POST, user=self.request.user) if form.validate(): wrongtime = WrongTime( user_id=self.request.user.id, date=form.popup_date.data, explanation=form.popup_explanation.data, ) DBSession.add(wrongtime) LOG(u"WrongTime added") response = '%s %s' % (self._(u'Explanation added'), CHANGE_STATUS % self._('Waits for verification')) return Response(response) return dict(form=form)
def post(self): timeentry = self.v['timeentry'] next_ = self.request.GET.get('next') if not next_: next_ = self.request.url_for( '/times/list', date=timeentry.date.strftime('%d.%m.%Y'), ) form = TimeEntryForm(self.request.POST, obj=timeentry) date = timeentry.date today = datetime.date.today() if form.validate(): if timeentry.project_id != int( form.project_id.data) and today > date: timeentry.deleted = True timeentry.modified_ts = datetime.datetime.now() time = TimeEntry(date=date, user_id=timeentry.user_id, time=form.time.data, description=form.description.data, ticket_id=form.ticket_id.data, project_id=form.project_id.data if form.project_id.data else None, timer_ts=datetime.datetime.now() if form.timer.data else None) DBSession.add(time) else: ticket_id = form.ticket_id.data if timeentry.time != form.time.data or\ timeentry.project_id != form.project_id.data: timeentry.modified_ts = datetime.datetime.now() timeentry.time = form.time.data timeentry.description = form.description.data timeentry.ticket_id = ticket_id timeentry.project_id = form.project_id.data if form.project_id.data else None self.flash(self._(u'Time entry saved')) LOG(u'Time entry saved') return HTTPFound(next_) return dict( timeentry_id=timeentry.id, form=form, date=date, next=next_, )
def add_time(cls, orig_bugs, sprint=None): """ @param orig_bugs: list of bugs Add times to bugs, can be used inside and outside the class. """ bugs = dict(((bug.id, bug.project_id), bug) for bug in orig_bugs if bug.project) where_condition = '(t.ticket_id = :bug_id_%s AND t.project_id = :project_id_%s)' conditions = [] params = {} i = 1 for bug_id, project_id in bugs: conditions.append(where_condition % (i, i)) params['bug_id_%s' % i] = bug_id params['project_id_%s' % i] = project_id i += 1 if not conditions: return orig_bugs # short circuit to avoid useless (and incorrect) SQL query condition = ' OR '.join(conditions) sql = """ SELECT t.ticket_id as "ticket_id", t.project_id as "project_id", SUM(t.time) as "time" FROM time_entry t WHERE t.deleted = FALSE AND (%s) GROUP BY t.ticket_id, t.project_id """ % (condition, ) query = DBSession.query('ticket_id', 'project_id', 'time').from_statement(sql).params(**params) for bug_id, project_id, time in query: bugs[(bug_id, project_id)].time = time if sprint: params['sprint_start'] = sprint.start params['sprint_end'] = sprint.end sql = """ SELECT t.ticket_id as "ticket_id", t.project_id as "project_id", SUM(t.time) as "time" FROM time_entry t WHERE t.deleted = FALSE AND (%s) AND t.date >= :sprint_start AND t.date <= :sprint_end GROUP BY t.ticket_id, t.project_id """ % (condition, ) query = DBSession.query( 'ticket_id', 'project_id', 'time').from_statement(sql).params(**params) for bug in bugs.itervalues(): bug.sprint_time = 0.0 for bug_id, project_id, time in query: bugs[(bug_id, project_id)].sprint_time = time return orig_bugs
def post(self): timeentry = self.v['timeentry'] next_ = self.request.GET.get('next') if not next_: next_ = self.request.url_for( '/times/list', date=timeentry.date.strftime('%d.%m.%Y'), ) form = TimeEntryForm(self.request.POST, obj=timeentry) date = timeentry.date today = datetime.date.today() if form.validate(): if timeentry.project_id != int(form.project_id.data) and today > date: timeentry.deleted = True timeentry.modified_ts = datetime.datetime.now() time = TimeEntry( date=date, user_id = timeentry.user_id, time = form.time.data, description = form.description.data, ticket_id = form.ticket_id.data, project_id = form.project_id.data if form.project_id.data else None, timer_ts = datetime.datetime.now() if form.timer.data else None ) DBSession.add(time) else: ticket_id = form.ticket_id.data if timeentry.time != form.time.data or\ timeentry.project_id != form.project_id.data: timeentry.modified_ts = datetime.datetime.now() timeentry.time = form.time.data timeentry.description = form.description.data timeentry.ticket_id = ticket_id timeentry.project_id = form.project_id.data if form.project_id.data else None self.flash(self._(u'Time entry saved')) LOG(u'Time entry saved') return HTTPFound(next_) return dict( timeentry_id=timeentry.id, form=form, date=date, next=next_, )
class Team(ApiView): def get(self): team_id = self.request.matchdict.get('team_id') team = Team_m.query.get(team_id) if team: return team.to_dict() else: raise HTTPNotFound() @has_perm('can_edit_teams') def put(self): team_id = self.request.matchdict.get('team_id') team = Team_m.query.get(team_id) if not team: raise HTTPNotFound() try: json_team = self.request.json_body except ValueError: raise HTTPBadRequest('Expect json') team_schema = TeamUpdateSchema() try: team_des = team_schema.deserialize(json_team) except colander.Invalid, e: errors = e.asdict() raise HTTPBadRequest(errors) team.name = team_des.get('name') or team.name if 'users' in team_des: new_users = team_des['users'] old_users = DBSession.query(TeamMember.user_id).filter(TeamMember.team_id==team.id).all() users_delete = list(set(old_users) - set(new_users)) users_add = list(set(new_users) - set(old_users)) if users_delete: TeamMember.query.filter(TeamMember.team_id==team.id)\ .filter(TeamMember.user_id.in_(users_delete))\ .delete(synchronize_session=False) if users_add: DBSession.add_all([TeamMember(user_id=u_id, team_id=team.id) for u_id in users_add]) if team_des.get('swap_with_preview'): preview = Preview(self.request) if not preview.swap_avatar(type='teams', id=team.id): raise HTTPBadRequest('No preview to swap') return HTTPOk("OK")
def post(self): form = LateJustificationForm(self.request.POST, user=self.request.user) if form.validate(): late = Late( user_id=self.request.user.id, date=form.popup_date.data, explanation=form.popup_explanation.data, ) DBSession.add(late) LOG(u"Late added") return Response(self._(u'Explanation added') + CHANGE_STATUS % self._('Waits for verification')) return dict(form=form)
def __call__(self, *args, **kwargs): config = ApplicationConfig.get_current_config(allow_empty=True) if config is None: WARN(u'Application config not found, emails cannot be checked') return trackers = dict( (tracker.mailer, tracker) for tracker in Tracker.query.filter( Tracker.mailer != None).filter(Tracker.mailer != '')) if not len(trackers): WARN( u'No trackers have mailers configured, email will not be checked' ) return username = config.google_user_email.encode('utf-8') password = config.google_user_password.encode('utf-8') # TODO logins_mappings = dict( (tracker.id, TrackerCredentials.get_logins_mapping(tracker)) for tracker in trackers.itervalues()) selector_mappings = dict((tracker.id, SelectorMapping(tracker)) for tracker in trackers.itervalues()) # find all projects connected to the tracker projects = dict( (project.id, project) for project in Project.query.all()) # all pre-conditions should be checked by now # start fetching fetcher = MailFetcher( username, password, ) # ok, we have all mails, lets create timeentries from them extractor = TimeEntryMailExtractor( trackers, logins_mappings, projects, selector_mappings, ) for msg in fetcher: timeentry = extractor.get(msg) if timeentry: DBSession.add(timeentry) transaction.commit()
def dispatch(self): sprint_id = self.request.GET.get('sprint_id') sprint = Sprint.query.get(sprint_id) form = DeleteForm(self.request.POST) if self.request.method == 'POST' and form.validate(): DBSession.delete(sprint) back_url = self.request.url_for('/scrum/sprint/list') return HTTPFound(location=back_url) return dict( type_name=u'sprint', title=u'%s' % sprint.name, url=self.request.url_for('/scrum/sprint/delete', sprint_id=sprint.id), back_url=self.request.url_for('/scrum/sprint/list'), form=form )
def action(self): config_obj = ApplicationConfig.get_current_config() client = SpreadsheetConnector(config_obj.google_user_email, config_obj.google_user_password) worksheet = client.get_worksheet(config_obj.holidays_spreadsheet, 6) data = worksheet.GetRecords(1, 99999) # Magic Constant dates_new = set([ datetime.datetime.strptime(d.content['data'], '%Y-%m-%d').date() for d in data ]) dates_old = set(Holiday.all(cache=False)) dates_diff = dates_new.difference(dates_old) if dates_diff: holidays = [ Holiday(date=date) for date in dates_diff ] DBSession.add_all(holidays) INFO(u'%s Holidays added: %s' % (len(dates_diff), dates_diff)) return Response('ok')
def post(self): _id = self.request.POST.get('id') name = self.request.POST.get('name') val = self.request.POST.get('val') val = bool(int(val)) if name == 'late': late = m.Late.query.get(_id) late.justified = val DBSession.add(late) elif name == 'wrongtime': wrongtime = m.WrongTime.query.get(_id) wrongtime.justified = val DBSession.add(wrongtime) return Response('')
def delete(self): board_id = self.request.matchdict.get('board_id') board = m.SprintBoard.query.get(board_id) if not board: raise HTTPNotFound() can_delete = (board.user_id == self.request.user.id) if not can_delete: raise HTTPForbidden DBSession.delete(board) return HTTPOk('OK')
def post(self): form = LateJustificationForm(self.request.POST, user=self.request.user) if form.validate(): late = Late( user_id=self.request.user.id, date=form.popup_date.data, explanation=form.popup_explanation.data, ) DBSession.add(late) LOG(u"Late added") return Response( self._(u'Explanation added') + CHANGE_STATUS % self._('Waits for verification')) return dict(form=form)
def get(self): user_id = self.request.GET.get('user_id') month_start, month_end = self._get_month() user = User.query.filter(User.id == user_id).one() query = DBSession.query('date', 'incorrect_count').from_statement(""" SELECT date, COUNT(date) as incorrect_count FROM time_entry s WHERE DATE(s.modified_ts) > s.date AND s.user_id = :user_id AND s.date >= :month_start AND s.date <= :month_end GROUP BY date """).params(month_start=month_start, month_end=month_end, user_id=user.id) data = query.all() data = self._group_by_user_monthly(data, user.id) holidays = Holiday.all() return dict( data=data, user=user, is_holiday=lambda date: Holiday.is_holiday(date, holidays=holidays ), month_start=month_start, month_end=month_end, next_month=next_month(month_start), prev_month=previous_month(month_start), datetime=datetime, )