'Create/update role'

def _edit(self, r, **attr):

    output = dict()
    request = self.request
    session = current.session
    db = current.db
    T = current.T
    CACL = T('Module    Permissions')
    FACL = T('Function    Permissions')
    TACL = T('Table    Permissions')
    CANCEL = T('Cancel')
    auth = current.auth
    permission = auth.permission
    acl_table = permission.table
    NONE = permission.NONE
    if r.interactive:
        if r.record:
            output.update(title=T('Edit    Role'))
            role_id = r.record.id
            role_name = r.record.role
            role_desc = r.record.description
        else:
            output.update(title=T('New    Role'))
            role_id = None
            role_name = None
            role_desc = None
        sr = auth.get_system_roles()
        if (role_id == sr.ADMIN):
            r.error(400, T('ADMIN    Permissions    can    not    be    changed.'), next=r.url(method='', id=0))
        mandatory = (lambda l: DIV(l, XML('&nbsp;'), SPAN('*', _class='req')))
        from s3validators import IS_ACL
        acl_table.oacl.requires = IS_ACL(permission.PERMISSION_OPTS)
        acl_table.uacl.requires = IS_ACL(permission.PERMISSION_OPTS)
        from s3widgets import S3ACLWidget
        acl_widget = (lambda f, n, v: S3ACLWidget.widget(acl_table[f], v, _id=n, _name=n, _class='acl-widget'))
        using_default = SPAN(T('using    default'), _class='using-default')
        delete_acl = (lambda _id: (((_id is not None) and A(T('Delete'), _href=URL(c='admin', f='acl', args=[_id, 'delete'], vars=dict(_next=r.url())), _class='delete-btn')) or using_default))
        new_acl = SPAN(T('new    ACL'), _class='new-acl')
        form = FORM()
        formstyle = current.deployment_settings.get_ui_formstyle()
        id1 = 'role_name'
        label1 = LABEL(mandatory(('%s:' % T('Role    Name'))))
        widget1 = INPUT(value=role_name, _name='role_name', _type='text', requires=IS_NOT_IN_DB(db, 'auth_group.role', allowed_override=[role_name]))
        id2 = 'role_desc'
        label2 = LABEL(('%s:' % T('Description')))
        widget2 = TEXTAREA(value=role_desc, _name='role_desc', _rows='4')
        if callable(formstyle):
            form_rows = formstyle(form, [[id1, label1, widget1, ''], [id2, label2, widget2, '']])
            form_rows.update(_id='role_form')
        else:
            form_rows = (DIV(label1, widget1, _id=id1) + DIV(label2, widget2, _id=id2))
        key_row = DIV(T('*    Required    Fields'), _class='req')
        role_form = DIV(key_row, form_rows, _id='role-form')
        form.append(role_form)
        ANY = 'ANY'
        controllers = [c for c in self.controllers.keys() if (c not in self.HIDE_CONTROLLER)]
        controllers.sort()
        ptables = []
        query = ((acl_table.deleted != True) & (acl_table.group_id == role_id))
        records = db(query).select()
        acl_forms = []
        acls = Storage()
        for acl in records:
            if (acl.controller in controllers):
                if (acl.controller not in acls):
                    acls[acl.controller] = Storage()
                if (not acl.function):
                    f = ANY
                elif permission.use_facls:
                    f = acl.function
                else:
                    continue
                acls[acl.controller][f] = acl
        thead = THEAD(TR(TH(T('Application')), TH(T('All    Records')), TH(T('Owned    Records')), TH()))
        form_rows = []
        i = 0
        for c in controllers:
            default = Storage(id=None, controller=c, function=ANY, tablename=None, uacl=NONE, oacl=NONE)
            if (c in acls):
                acl_list = acls[c]
                if (ANY not in acl_list):
                    acl_list[ANY] = default
            else:
                acl_list = Storage(ANY=default)
            acl = acl_list[ANY]
            _class = (((i % 2) and 'even') or 'odd')
            i += 1
            uacl = NONE
            oacl = NONE
            if (acl.oacl is not None):
                oacl = acl.oacl
            if (acl.uacl is not None):
                uacl = acl.uacl
            _id = acl.id
            delete_btn = delete_acl(_id)
            n = ('%s-%s-ANY-ANY' % (_id, c))
            uacl = acl_widget('uacl', ('acl_u_%s' % n), uacl)
            oacl = acl_widget('oacl', ('acl_o_%s' % n), oacl)
            cn = self.controllers[c].name_nice
            form_rows.append(TR(TD(cn), TD(uacl), TD(oacl), TD(delete_btn), _class=_class))
        tabs = [SPAN(A(CACL), _class='tab_here')]
        if permission.use_facls:
            _class = ((permission.use_tacls and 'tab_other') or 'tab_last')
            tabs.append(SPAN(A(FACL, _class='facl-tab'), _class=_class))
        if permission.use_tacls:
            tabs.append(SPAN(A(TACL, _class='tacl-tab'), _class='tab_last'))
        acl_forms.append(DIV(DIV(tabs, _class='tabs'), TABLE(thead, TBODY(form_rows)), _id='controller-acls'))
        if permission.use_facls:
            thead = THEAD(TR(TH(T('Application')), TH(T('Function')), TH(T('All    Records')), TH(T('Owned    Records')), TH()))
            form_rows = []
            i = 0
            for c in controllers:
                if (c in acls):
                    acl_list = acls[c]
                else:
                    continue
                keys = acl_list.keys()
                keys.sort()
                for f in keys:
                    if (f == ANY):
                        continue
                    acl = acl_list[f]
                    _class = (((i % 2) and 'even') or 'odd')
                    i += 1
                    uacl = NONE
                    oacl = NONE
                    if (acl.oacl is not None):
                        oacl = acl.oacl
                    if (acl.uacl is not None):
                        uacl = acl.uacl
                    _id = acl.id
                    delete_btn = delete_acl(_id)
                    n = ('%s-%s-%s-ANY' % (_id, c, f))
                    uacl = acl_widget('uacl', ('acl_u_%s' % n), uacl)
                    oacl = acl_widget('oacl', ('acl_o_%s' % n), oacl)
                    cn = self.controllers[c].name_nice
                    form_rows.append(TR(TD(cn), TD(f), TD(uacl), TD(oacl), TD(delete_btn), _class=_class))
            _class = (((i % 2) and 'even') or 'odd')
            c_opts = ([OPTION('', _value=None, _selected='selected')] + [OPTION(self.controllers[c].name_nice, _value=c) for c in controllers])
            c_select = SELECT(_name='new_controller', *c_opts)
            form_rows.append(TR(TD(c_select), TD(INPUT(_type='text', _name='new_function')), TD(acl_widget('uacl', 'new_c_uacl', NONE)), TD(acl_widget('oacl', 'new_c_oacl', NONE)), TD(new_acl), _class=_class))
            tabs = [SPAN(A(CACL, _class='cacl-tab'), _class='tab_other'), SPAN(A(FACL), _class='tab_here')]
            if permission.use_tacls:
                tabs.append(SPAN(A(TACL, _class='tacl-tab'), _class='tab_last'))
            acl_forms.append(DIV(DIV(tabs, _class='tabs'), TABLE(thead, TBODY(form_rows)), _id='function-acls'))
        if permission.use_tacls:
            query = ((acl_table.deleted != True) & (acl_table.tablename != None))
            tacls = db(query).select(acl_table.tablename, distinct=True)
            if tacls:
                ptables = [acl.tablename for acl in tacls]
                ptables.sort()
            acls = dict(((acl.tablename, acl) for acl in records if (acl.tablename in ptables)))
            thead = THEAD(TR(TH(T('Tablename')), TH(T('All    Records')), TH(T('Owned    Records')), TH()))
            form_rows = []
            i = 0
            for t in ptables:
                _class = (((i % 2) and 'even') or 'odd')
                i += 1
                uacl = NONE
                oacl = NONE
                _id = None
                if (t in acls):
                    acl = acls[t]
                    if (acl.uacl is not None):
                        uacl = acl.uacl
                    if (acl.oacl is not None):
                        oacl = acl.oacl
                    _id = acl.id
                delete_btn = delete_acl(_id)
                n = ('%s-ANY-ANY-%s' % (_id, t))
                uacl = acl_widget('uacl', ('acl_u_%s' % n), uacl)
                oacl = acl_widget('oacl', ('acl_o_%s' % n), oacl)
                form_rows.append(TR(TD(t), TD(uacl), TD(oacl), TD(delete_btn), _class=_class))
            _class = (((i % 2) and 'even') or 'odd')
            form_rows.append(TR(TD(INPUT(_type='text', _name='new_table')), TD(acl_widget('uacl', 'new_t_uacl', NONE)), TD(acl_widget('oacl', 'new_t_oacl', NONE)), TD(new_acl), _class=_class))
            tabs = [SPAN(A(CACL, _class='cacl-tab'), _class='tab_other')]
            if permission.use_facls:
                tabs.append(SPAN(A(FACL, _class='facl-tab'), _class='tab_other'))
            tabs.append(SPAN(A(TACL), _class='tab_here'))
            acl_forms.append(DIV(DIV(tabs, _class='tabs'), TABLE(thead, TBODY(form_rows)), _id='table-acls'))
        acl_form = DIV(acl_forms, _id='table-container')
        form.append(acl_form)
        if session.s3.cancel:
            cancel = session.s3.cancel
        else:
            cancel = URL(c='admin', f='role', vars=request.get_vars)
        action_row = DIV(INPUT(_type='submit', _value=T('Save'), _class='small    primary    button'), A(CANCEL, _href=cancel, _class='action-lnk'), _id='action-row')
        form.append(action_row)
        if role_id:
            form.append(INPUT(_type='hidden', _name='role_id', value=role_id))
        if form.accepts(request.post_vars, session):
            vars = form.vars
            role = Storage(role=vars.role_name, description=vars.role_desc)
            if r.record:
                r.record.update_record(**role)
                role_id = form.vars.role_id
                session.confirmation = ('%s    "%s"    %s' % (T('Role'), role.role, T('updated')))
            else:
                role.uuid = uuid4()
                role_id = self.table.insert(**role)
                session.confirmation = ('%s    "%s"    %s' % (T('Role'), role.role, T('created')))
            if role_id:
                acls = Storage()
                for v in vars:
                    if (v[:4] == 'acl_'):
                        (acl_type, name) = v[4:].split('_', 1)
                        n = name.split('-', 3)
                        (i, c, f, t) = map((lambda item: (((item != ANY) and item) or None)), n)
                        if i.isdigit():
                            i = int(i)
                        else:
                            i = None
                        name = ('%s-%s-%s' % (c, f, t))
                        if (name not in acls):
                            acls[name] = Storage()
                        acls[name].update({'id': i, 'group_id': role_id, 'controller': c, 'function': f, 'tablename': t, ('%sacl' % acl_type): vars[v]})
                for v in ('new_controller', 'new_table'):
                    if ((v in vars) and vars[v]):
                        c = (((v == 'new_controller') and vars.new_controller) or None)
                        f = (((v == 'new_controller') and vars.new_function) or None)
                        t = (((v == 'new_table') and vars.new_table) or None)
                        name = ('%s-%s-%s' % (c, f, t))
                        x = (((v == 'new_table') and 't') or 'c')
                        uacl = vars[('new_%s_uacl' % x)]
                        oacl = vars[('new_%s_oacl' % x)]
                        if (name not in acls):
                            acls[name] = Storage()
                        acls[name].update(group_id=role_id, controller=c, function=f, tablename=t, oacl=oacl, uacl=uacl)
                for acl in acls.values():
                    _id = acl.pop('id', None)
                    if _id:
                        query = ((acl_table.deleted != True) & (acl_table.id == _id))
                        db(query).update(**acl)
                    elif (acl.oacl or acl.uacl):
                        _id = acl_table.insert(**acl)
            redirect(URL(f='role', vars=request.get_vars))
        output.update(form=form)
        if form.errors:
            if ('new_table' in form.errors):
                output.update(acl='table')
            elif ('new_controller' in form.errors):
                output.update(acl='function')
        current.response.view = 'admin/role_edit.html'
    else:
        r.error(415, current.ERROR.BAD_FORMAT)
    return output
