예제 #1
0
def change_pr_approval (db, cl, nodeid, new_values) :
    common.require_attributes \
        (_, cl, nodeid, new_values, 'purchase_request', 'order')
    app = cl.getnode (nodeid)
    rol = new_values.get ('role',    cl.get (nodeid, 'role'))
    rid = new_values.get ('role_id', cl.get (nodeid, 'role_id'))
    if rol and not rid :
        new_values ['role_id'] = db.pr_approval_order.lookup (rol)
    if 'status' in new_values :
        pr_open      = db.pr_status.lookup ('open')
        pr_approving = db.pr_status.lookup ('approving')
        os = app.status
        ns = new_values ['status']
        if os != ns :
            pr = db.purchase_request.getnode (app.purchase_request)
            if pr.status not in (pr_open, pr_approving) :
                raise Reject (_ ("No change of approvals for this PR"))
            new_values ['by']   = db.getuid ()
            new_values ['date'] = Date ('.')
            approvals = cl.filter (None, dict (purchase_request = pr.id))
            assert nodeid in approvals
    elif new_values.keys () == ['role_id'] :
        n = db.pr_approval_order.get (new_values ['role_id'], 'role')
        if cl.get (nodeid, 'role') != n :
            raise Reject ("Inconsistent role_id")
    elif app.status != db.pr_approval_status.lookup ('undecided') :
        raise Reject (_ ("May not change approval status parameters"))
    elif 'msg' in new_values and new_values ['msg'] is not None :
        # Don't link random message to approval if status isn't changing
        del new_values ['msg']
예제 #2
0
def check_range(db, nodeid, uid, first_day, last_day):
    """ Check length of range and if there are any records in the given
        time-range for this user. This means either the first day of an
        existing record is inside the new range or the last day is
        inside the new range or the first day is lower than the first
        day *and* the last day is larger (new interval is contained in
        existing interval).
    """
    if first_day > last_day:
        raise Reject(_("First day may not be after last day"))
    if (last_day - first_day) > Interval('30d'):
        raise Reject(_("Max. 30 days for single leave submission"))
    range = common.pretty_range(first_day, last_day)
    both = (first_day.pretty(';%Y-%m-%d'), last_day.pretty('%Y-%m-%d;'))
    stati = [
        x for x in db.leave_status.getnodeids(retired=False)
        if db.leave_status.get(x, 'name') not in ('declined', 'cancelled')
    ]
    for f, l in ((range, None), (None, range), both):
        d = dict(user=uid, status=stati)
        if f:
            d['first_day'] = f
        if l:
            d['last_day'] = l
        r = [x for x in db.leave_submission.filter(None, d) if x != nodeid]
        if r:
            raise Reject \
                (_ ("You already have vacation requests in this time range"))
예제 #3
0
def check_tp_cc_consistency (db, cl, nodeid, new_values, org = None) :
    """ Check that the organisation in tp or cc is correct and
        consistent with the organisation stored in the PR.
        Also check that the tp or cc is valid.
    """
    pr  = cl.getnode (nodeid)
    tc  = new_values.get ('time_project', pr.time_project)
    cc  = new_values.get ('sap_cc', pr.sap_cc)
    # Can happen only for order item:
    if not tc and not cc :
        return
    org = org or pr.organisation
    if tc :
        node = db.time_project.getnode (tc)
        st   = db.time_project_status.getnode (node.status)
        if not st.active :
            time_project = _ ('time_project')
            name = node.name + ' ' + node.description
            raise Reject \
                (_ ("Non-active %(time_project)s: %(name)s") % locals ())
    else :
        node = db.sap_cc.getnode (cc)
        if not node.valid :
            sap_cc = _ ('sap_cc')
            name   = node.name
            raise Reject (_ ("Invalid %(sap_cc)s: %(name)s") % locals ())
    if node.organisation != org :
        o1 = db.organisation.get (org, 'name')
        if not node.organisation :
            raise Reject (_ ("Organisation of CC/TC is empty"))
        o2 = db.organisation.get (node.organisation, 'name')
        raise Reject \
            ( _("Organisation must be consistent with CC/TC: got %s expect %s")
            % (o1, o2)
            )
예제 #4
0
def _audit_update_active(db, c, nodeid, newvalues):
    new_status = newvalues.get('status')
    old_status = c.get(nodeid, 'status')
    if new_status == old_status:
        return
    # Prepare auxiliary data
    for id in db.cstatus.list():
        title = db.cstatus.get(id, 'title')
        if title == 'open':
            s_open = id
        elif title == 'done':
            s_done = id
        elif title == 'n/a':
            s_na = id
        elif title == 'inactive':
            s_inactive = id
        else:
            raise Exception('title: %s' % title)
    closed_statuses = (
        s_done,
        s_na,
    )
    # Find reverse dependencies
    dependencies = {}
    all_ids = c.list()
    for id in all_ids:
        dependencies[id] = []
    for id in all_ids:
        for dep_id in c.get(id, 'prereq'):
            dependencies[dep_id].append(id)
    # If activated, check it doesn't break dependencies
    if old_status == s_inactive:
        for id in c.get(nodeid, 'prereq'):
            if c.get(id, 'status') not in closed_statuses:
                raise Reject("Prerequisity checkpoint not yet completed: %s" %
                             (c.get(id, 'title'), ))
    # If deactivated, check it doesn't break dependencies
    if new_status == s_inactive:
        for id in dependencies[nodeid]:
            if c.get(id, 'status') in closed_statuses:
                raise Reject("Dependent checkpoint already closed: %s" %
                             (c.get(id, 'title'), ))
    # If deactivated or reopened, deactivate open dependants
    if new_status in (
            s_inactive,
            s_open,
    ):
        for id in dependencies[nodeid]:
            if c.get(id, 'status') == s_open:
                c.set(id, status=s_inactive)
    # If closed, activate inactive dependants
    if new_status in closed_statuses and old_status not in closed_statuses:
        for id in dependencies[nodeid]:
            if c.get(id, 'status') == s_inactive:
                for dep_id in c.get(id, 'prereq'):
                    if dep_id != nodeid and c.get(
                            dep_id, 'status') not in closed_statuses:
                        break
                else:
                    c.set(id, status=s_open)
예제 #5
0
def find_time_records(db, cl, nodeid, new_values):
    """ Search for existing time records when start/end date changes.
        Reject if valid records other than public holidays are found.
    """
    if 'valid_to' not in new_values and 'valid_from' not in new_values:
        return
    dyn = cl.getnode(nodeid)
    valid_to = new_values.get('valid_to')
    valid_from = new_values.get('valid_from')
    next = user_dynamic.next_user_dynamic(db, dyn)
    prev = user_dynamic.prev_user_dynamic(db, dyn)
    to = next and (next.valid_from - common.day)
    frm = prev and (prev.valid_to)
    ranges = dict \
        ( valid_to   = common.pretty_range (valid_to, to)
        , valid_from = common.pretty_range (frm, valid_from - common.day)
        )
    gaps = dict \
        ( valid_to   = not next or next.valid_from > valid_to
        , valid_from = not prev or prev.valid_to   < valid_from
        )
    msgs = dict \
        ( valid_to   = _
            ( "There are (non public holiday) "
              "time records at or after %s"
            )
        , valid_from = _
            ( "There are (non public holiday) "
              "time records before %s"
            )
        )
    for k in ('valid_to', 'valid_from'):
        value = new_values.get(k)
        if value is not None and gaps[k]:
            trs = db.time_record.filter \
                ( None
                , { 'daily_record.user': dyn.user
                  , 'daily_record.date': ranges [k]
                  }
                )
            # loop for checking if time recs are public holiday
            for id in trs:
                tr = db.time_record.getnode(id)
                # case where no wp was entered yet
                if tr.wp is None:
                    raise Reject(msgs[k] % value.pretty(common.ymd))
                # case where wp was set
                wp = db.time_wp.getnode(tr.wp)
                tc = db.time_project.getnode(wp.project)
                if not tc.is_public_holiday:
                    raise Reject(msgs[k] % value.pretty(common.ymd))
            # loop entirely for retiring public holidys
            for id in trs:
                tr = db.time_record.getnode(id)
                assert tr.wp
                wp = db.time_wp.getnode(tr.wp)
                tc = db.time_project.getnode(wp.project)
                assert tc.is_public_holiday
                db.time_record.retire(id)
예제 #6
0
def new_pr_approval (db, cl, nodeid, new_values) :
    common.require_attributes \
        (_, cl, nodeid, new_values, 'purchase_request', 'order')
    if  (   not new_values.get ('user', None)
        and not new_values.get ('role', None)
        ) :
        raise Reject (_ ("user or role required"))
    if 'role' in new_values and 'role_id' not in new_values :
        raise Reject (_ ("No role id"))
    new_values ['status'] = db.pr_approval_status.lookup ('undecided')
예제 #7
0
def check_wp(db, wp_id, user, first_day, last_day, comment):
    wp = db.time_wp.getnode(wp_id)
    tp = db.time_project.getnode(wp.project)
    if not tp.approval_required:
        raise Reject(_("No approval required for work package"))
    if not wp.is_public and user not in wp.bookers:
        raise Reject(_("User may not book on work package"))
    if first_day < wp.time_start or wp.time_end and last_day > wp.time_end:
        raise Reject(_("Work package not valid during vacation time"))
    if tp.is_special_leave and not comment:
        raise Reject(_("Comment is required for special leave"))
예제 #8
0
def audit_user(db, c, nodeid, newvalues):
    if newvalues.get('username') not in (
            'admin',
            'anonymous',
    ):
        newvalues['roles'] = 'User'
    username = newvalues.get('username')
    if not username:
        Reject("Username may not be empty")
    if not re.match('^[a-z]+$', username):
        Reject("Only lowercase English letters allowed in username")
예제 #9
0
파일: project.py 프로젝트: brailcom/wausers
def _make_project (db, c, nodeid, newvalues):
    name = newvalues['project']
    if not newvalues.get ('user'):
        raise Reject ("No project creator given")
    # Create project directory
    project_directory = os.path.join (os.path.dirname (db.config.HOME), name)
    try:
        os.mkdir (project_directory)
    except OSError:
        raise Reject ("Project name <em>%s</em> is already taken" % (name,))
    # Create the project
    try:
        # Create project directory
        template = 'waassistant'
        template_directory = os.path.dirname (project_directory)
        templates = roundup.init.listTemplates (template_directory)
        if not templates.has_key (template):
            raise Exception ("Template `waassistant' unavailable")
        roundup.init.install (project_directory, templates[template]['path'])
        # Update config file
        url = os.path.dirname (os.path.dirname (db.config.TRACKER_WEB)) + '/' + name + '/'
        config_file = os.path.join (project_directory, 'config.ini')
        config_file_tmp = config_file + '.tmp'
        os.rename (config_file, config_file_tmp)
        infile, outfile = open (config_file_tmp), open (config_file, 'w')
        for line in infile:
            if re.match ('^#?web =', line):
                line = 'web = %s\n' % (url,)
            elif re.match ('name =', line):
                line = 'name = %s\n' % (name,)
            outfile.write (line)
        infile.close (), outfile.close ()
        os.remove (config_file_tmp)
        # Initialize project
        f = open (os.path.join (os.path.join (db.config.TRACKER_HOME, 'db'), 'backend_name'))
        backend = f.read ()
        f.close ()
        try:
            tracker = roundup.instance.open (project_directory)
            if tracker.exists ():
                tracker.nuke ()
        except:
            pass
        roundup.init.write_select_db (project_directory, backend)
        tracker = roundup.instance.open (project_directory)
        tracker.init (roundup.password.Password ('dummypassword'))
    except Exception, e:
        try:
            os.rmdir (project_directory)
        except:
            pass
        raise Reject ("Project creation failed: %s" % (e,))
예제 #10
0
def check_metadata (db, cl, nodeid, new_values) :
    """ The metadata field should be in json.
        This field should have the following format:
        { 'system_name' : 'jira'
        , 'levels'      : [ { 'level' : 1
                            , 'level_name' : 'Project'
                            , 'name' : 'Project-Name'
                            , 'id' : '4711'
                          , ...
                          ]
        }
        Note that both, the top-level system_name and levels are
        required. In the levels array at least one member is required.
        The level is an integer value and levels must start with 1 and
        be tightly numbered (without jumps of the counter). The
        level_name and name of the respective item on that level depends
        on the remote system. The id is a string because some systems
        may use non-numeric ids here. The fields shown are all required,
        additional fields may be present.
    """
    if 'metadata' not in new_values :
        return
    metadata = new_values ['metadata']
    # Allow empty
    if not metadata :
        return
    obj = json.loads (metadata)
    if not isinstance (obj, type ({})) :
        raise Reject (_ ("Invalid metadata, object not a dict"))
    if 'system_name' not in obj or 'levels' not in obj :
        raise Reject (_ ("Invalid metadata, required fields missing"))
    if not isinstance (obj ['levels'], type ([])) :
        raise Reject (_ ("Invalid metadata, levels must be array"))
    for n, lvl in enumerate (obj ['levels']) :
        if not isinstance (lvl, type ({})) :
            raise Reject (_ ("Invalid metadata, level not a dict"))
        for k in 'level', 'level_name', 'name', 'id' :
            if k not in lvl :
                raise Reject \
                    (_ ('Invalid metadata, required field "%s" '
                        'in level missing'
                       )
                    % k
                    )
                if k != 'level' :
                    if not isinstance (lvl ['k'], type (u'')) :
                        raise Reject \
                            (_ ('Invalid metadata: %s: String expected') % k)
            if int (lvl ['level']) != n + 1 :
                raise Reject (_ ('Invalid metadata, level: expect: %d' % (n+1)))
예제 #11
0
def check_travel_flag (db, cl, nodeid, new_values) :
    """ Ensure that the travel flag cannot be set and that WPs with
        travel flag may not be resurrected (change the closed date)
    """
    # Allow 'admin' to do this anyway, needed for regression tests that
    # use a WP with travel set.
    if db.getuid () == '1' :
        return
    if new_values.get ('travel', False) :
        raise Reject ("Travel flag must not be set")
    if nodeid and 'time_end' in new_values :
        wp = db.time_wp.getnode (nodeid)
        if wp.travel and wp.time_end :
            raise Reject ("Travel WP may not be resurrected")
예제 #12
0
def audit_register_user (db, c, nodeid, newvalues):
    configuration = UserConfig (os.path.join (os.path.dirname (db.dir), 'configwa.ini'))
    wausers_path = configuration.WAUSERS_HOME
    if wausers_path:
        if not nodeid and not newvalues.has_key ('wausername'):
            if newvalues.get ('username') not in ('admin', 'anonymous',):
                if configuration.WAUSERS_SAME_LOGIN:
                    newvalues['wausername'] = newvalues.get ('username')
                else:
                    raise Reject ("No WAusers name given")
        if wausers_path not in sys.path:
            sys.path.append (wausers_path)
        import waauth
        if newvalues.has_key ('wausername'):
            if not waauth.check_user (newvalues['wausername'], configuration.WAUSERS_HOME):
                raise Reject ("WAusers name `%s' does not exist" % (newvalues['wausername'],))
def auto_wp_check(db, cl, nodeid, new_values):
    """ Check auto_wp properties
    """
    # These properties must not change:
    props = \
        ( 'contract_type'
        , 'org_location'
        , 'time_project'
        )
    if nodeid:
        for p in props:
            if p in new_values:
                raise Reject(_('Property "%s" must not change') % _(p))
    else:
        common.require_attributes \
            ( _, cl, nodeid, new_values
            , 'org_location'
            , 'time_project'
            , 'name'
            )
        if 'durations_allowed' not in new_values:
            new_values['durations_allowed'] = False
        if 'is_valid' not in new_values:
            new_values['is_valid'] = False
        if 'all_in' not in new_values:
            new_values['all_in'] = True
예제 #14
0
def requester_chg (db, cl, nodeid, new_values) :
    if 'requester' in new_values :
        st_rej  = db.pr_status.lookup ('rejected')
        st_open = db.pr_status.lookup ('open')
        ost = cl.get (nodeid, 'status')
        if ost != st_open and ost != st_rej :
            raise Reject (_ ("Requester may not be changed"))
예제 #15
0
def check_dyn_user_params(db, user, first_day, last_day):
    d = first_day
    ctype = -1  # contract_type is either None or a string, can't be numeric
    while d <= last_day:
        dyn = user_dynamic.get_user_dynamic(db, user, d)
        if not dyn:
            ymd = common.ymd
            raise Reject(_("No dynamic user data for %s") % d.pretty(ymd))
        if dyn.vacation_yearly is None:
            raise Reject(_("No yearly vacation for this user"))
        if dyn.vacation_day is None or dyn.vacation_month is None:
            raise Reject(_("Vacation date setting is missing"))
        if ctype != dyn.contract_type and ctype != -1:
            raise Reject(_("Differing contract types in range"))
        ctype = dyn.contract_type
        d += common.day
예제 #16
0
def creator_resolution(db, cl, nodeid, newvalues):
    '''Catch attempts to set the status to "resolved" - if the assignedto
    user isn't the creator, then set the status to "in-progress" (try
    "confirm-done" first though, but "classic" Roundup doesn't have that
    status)
    '''
    if 'status' not in newvalues:
        return

    # get the resolved state ID
    resolved_id = db.status.lookup('resolved')

    if newvalues['status'] != resolved_id:
        return

    # check the assignedto
    assignedto = newvalues.get('assignedto', cl.get(nodeid, 'assignedto'))
    creator = cl.get(nodeid, 'creator')
    if assignedto == creator:
        if db.getuid() != creator:
            name = db.user.get(creator, 'username')
            raise Reject('Only the creator (%s) may close this issue' % name)
        return

    # set the assignedto and status
    newvalues['assignedto'] = creator
    try:
        status = db.status.lookup('confirm-done')
    except KeyError:
        status = db.status.lookup('in-progress')
    newvalues['status'] = status
예제 #17
0
def check_correction(db, cl, nodeid, new_values):
    common.require_attributes \
        (_, cl, nodeid, new_values, 'user', 'date', 'day')
    if nodeid:
        common.require_attributes \
            (_, cl, nodeid, new_values, 'absolute')
    else:
        if 'absolute' not in new_values:
            new_values['absolute'] = False
    user = new_values.get('user')
    if user is None:
        user = cl.get(nodeid, 'user')
    if 'date' in new_values:
        new_values['date'] = common.fix_date(new_values['date'])
    date = new_values.get('date')
    if date is None:
        date = cl.get(nodeid, 'date')
    if freeze.frozen(db, user, date):
        # Allow admin to add (initial) absolute correction
        if (nodeid is not None or db.getuid() != '1'
                or not new_values.get('absolute')):
            raise Reject(_("Frozen"))
    # Check that vacation parameters exist in dyn. user records
    dyn = user_dynamic.act_or_latest_user_dynamic(db, user)
    if not dyn or dyn.valid_to and dyn.valid_to < date:
        username = db.user.get(user, 'username')
        raise Reject \
            (_ ('No current dyn. user record for "%(username)s"') % locals ())
    while dyn and (not dyn.valid_to or dyn.valid_to > date):
        if (dyn.vacation_yearly is None or not dyn.vacation_month
                or not dyn.vacation_day):
            raise Reject \
                (_ ('Missing vacation parameters in dyn. user record(s)'))
        dyn = user_dynamic.prev_user_dynamic(db, dyn)
예제 #18
0
def check_retire (db, cl, nodeid, new_values) :
    assert not new_values
    uid      = db.getuid ()
    st_open  = db.daily_record_status.lookup ('open')
    st_leave = db.daily_record_status.lookup ('leave')
    tr = cl.getnode (nodeid)
    dr = db.daily_record.getnode (tr.daily_record)
    if frozen (db, dr.user, dr.date) :
        raise Reject (_ ("Can't retire frozen time record"))
    tt_by = db.user.get (dr.user, 'timetracking_by')
    allowed = True
    if dr.status == st_open :
        if  (   uid != dr.user
            and uid != tt_by
            and not common.user_has_role (db, uid, 'controlling', 'admin')
            ) :
            # Must have a leave submission in status accepted, then we
            # can retire existing records
            ac = db.leave_status.lookup ('accepted')
            vs = vacation.leave_submissions_on_date \
                (db, dr.user, dr.date, filter = dict (status = ac))
            if not vs :
                allowed = False
    else :
        if dr.status == st_leave :
            # All leave submissions must be in state cancelled or declined
            # At least one must be cancelled
            cn = db.leave_status.lookup ('cancelled')
            dc = db.leave_status.lookup ('declined')
            vs = vacation.leave_submissions_on_date (db, dr.user, dr.date)
            if not vs :
                allowed = False
            if allowed :
                allowed = False
                for v in vs :
                    if v.status == dc :
                        continue
                    if v.status == cn :
                        allowed = True
                    if v.status != cn :
                        allowed = False
                        break
        else :
            allowed = False
    # Allow admin to retire any time_record (!)
    if not allowed and db.getuid () != '1' :
        raise Reject (_ ("Permission denied"))
예제 #19
0
def new_submission(db, cl, nodeid, new_values):
    """ Check that new leave submission is allowed and has sensible
        parameters
    """
    common.reject_attributes(_, new_values, 'approval_hr', 'comment_cancel')
    uid = db.getuid()
    st_subm = db.leave_status.lookup('submitted')
    if 'user' not in new_values:
        user = new_values['user'] = uid
    else:
        user = new_values['user']
    common.require_attributes \
        (_, cl, nodeid, new_values, 'first_day', 'last_day', 'user')
    first_day = new_values['first_day']
    last_day = new_values['last_day']
    fix_dates(new_values)
    if 'time_wp' not in new_values:
        wps = vacation.valid_leave_wps \
            ( db
            , user
            , last_day
            , [('-', 'project.is_vacation'), ('-', 'project.approval_hr')]
            )
        if wps:
            new_values['time_wp'] = wps[0]

    common.require_attributes(_, cl, nodeid, new_values, 'time_wp')
    if freeze.frozen(db, user, first_day):
        raise Reject(_("Frozen"))
    comment = new_values.get('comment')
    check_range(db, None, user, first_day, last_day)
    check_wp(db, new_values['time_wp'], user, first_day, last_day, comment)
    is_admin = (uid == '1')
    if 'status' in new_values and new_values[
            'status'] != st_subm and not is_admin:
        raise Reject(_('Initial status must be "submitted"'))
    if 'status' not in new_values:
        new_values['status'] = st_subm
    if (user != uid and
            not (is_admin or common.user_has_role(db, uid, 'HR-vacation'))):
        raise Reject \
            (_ ("Only special role may create submission for other user"))
    vacation.create_daily_recs(db, user, first_day, last_day)
    if vacation.leave_days(db, user, first_day, last_day) == 0:
        raise Reject(_("Vacation request for 0 days"))
    check_dr_status(db, user, first_day, last_day, 'open')
    check_dyn_user_params(db, user, first_day, last_day)
예제 #20
0
def audit_retire(db, c, nodeid, newvalues):
    for id in c.list():
        if id == nodeid:
            continue
        if id in c.get(nodeid, 'prereq'):
            raise Reject(
                "Deletion prevented since another checkpoint depends on this one: %s"
                % (id, ))
예제 #21
0
def check_name (db, cl, nodeid, new_values) :
    """ Ensure that names do not contain certain characters """
    forbidden = ',/"'
    if 'name' in new_values :
        name = new_values ['name']
        for c in forbidden :
            if c in name :
                raise Reject (_ ("Name contains forbidden character %s") % c)
예제 #22
0
def _check_location_values(db, c, nodeid, newvalues):
    # Empty URL?
    url = newvalues.get('url')
    if url == '' or (url is None and nodeid is None):
        raise Reject, "No URL given"
    if url[:len('http://')] != 'http://' and url[:len('https://'
                                                      )] != 'https://':
        raise Reject('URL does not start with http:// nor https://')
예제 #23
0
def check_epic_key (db, cl, nodeid, new_values) :
    """ Ensure that the epic_key matches the format of keys in Jira
    """
    if 'epic_key' in new_values :
        r = re.compile (r'^[A-Z][0-9A-Z_]+[0-9A-Z]-[0-9]+$')
        k = new_values ['epic_key']
        if k is not None and not r.search (k) :
            epickey = _ ('epic_key')
            raise Reject (_ ("Not a valid %(epickey)s: %(k)s") % locals ())
예제 #24
0
def check_pr_offer_item (db, cl, nodeid, new_values) :
    common.require_attributes \
        (_, cl, nodeid, new_values, 'units', 'price_per_unit')
    units = new_values.get ('units', None)
    price = new_values.get ('price_per_unit', None)
    oi    = None
    if nodeid :
        oi = cl.getnode (nodeid)
    if units is None :
        assert oi
        units = oi.units
    if price is None :
        assert oi
        price = oi.price_per_unit
    if units <= 0 :
        raise Reject ("Units must not be <= 0")
    if price <= 0 :
        raise Reject ("Price must not be <= 0")
예제 #25
0
def check_currency (db, cl, nodeid, new_values) :
    common.require_attributes \
        (_, cl, nodeid, new_values, 'min_sum', 'order', 'exchange_rate')
    if new_values.get ('key_currency') :
        for id in db.pr_currency.getnodeids () :
            if id == nodeid :
                continue
            if cl.get (id, 'key_currency') :
                raise Reject (_ ("Duplicate key currency"))
예제 #26
0
def common_user_checks(db, cl, nodeid, new_values):
    ''' Make sure user properties are valid.
        - email address has no spaces in it
        - roles specified exist
    '''
    if ('address' in new_values and new_values['address']
            and ' ' in new_values['address']):
        raise ValueError, 'Email address must not contain spaces'
    common.check_roles(db, cl, nodeid, new_values)
    # automatic setting of realname
    if 'firstname' in cl.properties:
        n = 'firstname'
        fn = new_values.get(n, None) or cl.get(nodeid, n) or ''
        n = 'lastname'
        ln = new_values.get(n, None) or cl.get(nodeid, n) or ''
        if (new_values.has_key("firstname") or new_values.has_key("lastname")):
            realname = " ".join((fn, ln))
            new_values["realname"] = realname
    if 'lunch_duration' in new_values:
        ld = new_values['lunch_duration']
        if ld * 3600 % 900:
            raise Reject, _("Times must be given in quarters of an hour")
        new_values['lunch_duration'] = int(ld * 4) / 4.
        if ld > 8:
            raise Reject, _("Lunchbreak of more than 8 hours? Sure?")
        if ld < .5:
            raise Reject, _("Lunchbreak must be at least half an hour.")
    if 'lunch_start' in new_values:
        ls = new_values['lunch_start']
        ls = Date(ls)  # trigger date-spec error if this fails.
    if 'tt_lines' in new_values:
        ttl = new_values['tt_lines']
        if ttl < 1:
            new_values['tt_lines'] = 1
        if ttl > 5:
            new_values['tt_lines'] = 5
    if 'supervisor' in new_values:
        common.check_loop \
            (_, cl, nodeid, 'supervisor', new_values ['supervisor'])
    # Allow nickname to be empty
    # Nick must be unique and must not collide with a username
    # This is checked in both directions
    if 'nickname' in new_values and new_values['nickname']:
        v = new_values['nickname']
        common.check_unique(_, cl, nodeid, nickname=v)
        common.check_unique(_, cl, nodeid, username=v)
    if 'nickname' in cl.properties and 'username' in new_values:
        common.check_unique(_, cl, nodeid, nickname=new_values['username'])
    for k in maxlen:
        if k in new_values:
            if new_values[k] is None:
                continue
            if len(new_values[k]) > maxlen[k]:
                fn = _(k)
                l = maxlen[k]
                raise Reject(_('%(fn)s too long: > %(l)s' % locals()))
예제 #27
0
def prjust (db, cl, nodeid, new_values) :
    """ Field pr_justification must be edited when signing
    """
    pjn = 'pr_justification'
    fn  = _ (pjn)
    pj  = new_values.get (pjn, cl.get (nodeid, pjn))
    if pj :
        for k, v in prlib.pr_justification :
            if v in pj :
                raise Reject (_ ("You must edit %(fn)s") % locals ())
예제 #28
0
    def handle(self):
        ''' Perform some action. No return value is required.
        '''
        if self.client.env['REQUEST_METHOD'] != 'POST':
            raise Reject(self._('Invalid request'))
        # parse the props from the form
        try:
            props, links = self.client.parsePropsFromForm(create=1)
        except (ValueError, KeyError) as message:
            self.client.add_error_message(self._('Error: %s') % str(message))
            return
        print props
        print props[('project', self.form['projectid'].value)]['supplier']
        try:
            message = self._editnodes(props, links)
        except (ValueError, KeyError, IndexError, Reject) as message:
            escape = not isinstance(message, RejectRaw)
            self.client.add_error_message(self._('Edit Error: %s') %
                                          str(message),
                                          escape=escape)
            return
        self.db.project.set(self.form['projectid'].value,
                            status='5')  # Set project status to 'in-progress'
        #insert task(s)
        for task in self.db.workflow.filter(None,
                                            filterspec={
                                                'workflowname': '1',
                                                'trg_type': None,
                                                'trg_state': None
                                            }):
            t = self.db.issue.create(
                project=self.form['projectid'].value,
                tasktype=self.db.workflow.get(task, 'new_type'),
                status='new',
                supplier=self.db.workflow.get(task, 'new_resp')
                if self.db.workflow.get(task, 'new_resp') else
                props[('project', self.form['projectid'].value)]['supplier'])
        # commit now that all the tricky stuff is done
        self.db.commit()

        # redirect to the item's edit page
        # redirect to finish off
        url = self.base + self.classname
        # note that this action might have been called by an index page, so
        # we will want to include index-page args in this URL too
        if self.nodeid is not None:
            url += self.nodeid
        url += '?@ok_message=%s&@template=%s' % (urllib_.quote(
            'Project%s launched.' %
            (self.form['projectid'].value)), urllib_.quote(self.template))
        if self.nodeid is None:
            req = templating.HTMLRequest(self.client)
            print self.form['projectid'].value
            url += '&' + req.indexargs_url('', {})[1:]
        raise exceptions.Redirect(url)
예제 #29
0
def check_issue_nums (db, cl, nodeid, new_values) :
    issue_ids = new_values.get ('issue_ids', None)
    # Allow empty value, also exits if not changed
    if issue_ids is None :
        return
    minl = int (getattr (db.config.ext, 'LINK_MINID', 0))
    maxl = int (getattr (db.config.ext, 'LINK_MAXID', 100))
    ids  = [x.strip () for x in issue_ids.split (',')]
    for id in ids :
        if not (minl <= len (id) <= maxl) or not id.isdigit () :
            raise Reject (_ ("Invalid Issue-Number: %s") % id)
예제 #30
0
def approvalchange (db, cl, nodeid, new_values) :
    if 'special_approval' not in new_values :
        return
    status = new_values.get ('status', cl.get (nodeid, 'status'))
    # In state open we do nothing at this point, the special approvals
    # will be processed later, in other states change of approvals is no
    # longer possible.
    if status == db.pr_status.lookup ('open') :
        return
    if status != db.pr_status.lookup ('approving') :
        raise Reject (_ ("Approval change only in state open and approving"))
    sa  = set (new_values ['special_approval'])
    osa = set (cl.get (nodeid, 'special_approval'))
    if osa - sa :
        raise Reject (_ ("Cannot remove users from approval list"))
    for uid in sa - osa :
        prlib.gen_pr_approval \
            ( db, True
            , purchase_request = nodeid
            , user             = uid
            , order            = 15
            , description      = _ ("Special approval")
            )