Bivio::Biz::Model::GroupUserForm
# Copyright (c) 2008-2010 bivio Software, Inc. All Rights Reserved. # $Id$ package Bivio::Biz::Model::GroupUserForm; use strict; use Bivio::Base 'Biz.FormModel'; my($_FM) = b_use('Type.FormMode'); my($_AUX) = [qw(is_subscribed file_writer)]; my($_R) = b_use('Auth.Role'); my($_F) = b_use('UI.Facade'); my($_UNAPPROVED) = $_R->UNAPPROVED_APPLICANT; my($_EVERYBODY) = b_use('Auth.Role')->get_category_role_group('everybody'); sub UNAPPROVED_ROLE { return $_UNAPPROVED; } sub USER_LIST_CLASS { return 'GroupUserList'; } sub can_add_user { my($self) = @_; return $self->new_other('GroupUserList')->can_add_user; } sub change_main_role { my($self, $user_id, $role) = @_; my($ru) = $self->new_other('RealmUser'); $ru->delete_all({ user_id => $user_id, role => $_EVERYBODY, }); $ru->create({ realm_id => $self->req('auth_id'), user_id => $user_id, role => $role, }) unless $role->eq_unknown; _audit_user($self, $user_id); return; } sub create_unapproved_applicant { my($self, $user_id) = @_; return $self->change_main_role($user_id, $self->UNAPPROVED_ROLE); } sub delete_all_roles { my($self, $user_id) = @_; return $self->change_main_role($user_id, $_R->UNKNOWN); } sub execute_empty { my($self) = @_; #TODO: Create version for site-user forum my($main, $aux) = $self->req('Model.' . $self->USER_LIST_CLASS) ->roles_by_category; $self->internal_put_field('RealmUser.role' => $main->[0]); foreach my $f (@{$self->internal_aux_fields}) { $self->internal_put_field( $f => $f eq 'is_subscribed' ? _do_subscribed( $self, 'unsafe_load', $self->get('RealmUser.user_id'), 1) : grep($_->equals_by_name($f), @$aux) ? 1 : 0, ); } return; } sub execute_ok { my($self) = @_; my($old_main); if (my $ul = $self->ureq('Model.' . $self->USER_LIST_CLASS)) { $old_main = $ul->roles_by_category->[0]; } else { $old_main = $self->get('current_main_role'); } my($uid) = $self->get('RealmUser.user_id'); my($main) = $self->get('RealmUser.role'); my($ru) = $self->new_other('RealmUser'); if ($main) { unless (($old_main || '') eq $main) { $ru->delete_all({user_id => $uid}); return _audit_user($self, $uid) if $main->eq_unknown; $ru->create({ user_id => $uid, role => $main, }); } #TODO: Deal with the site level (invalidate password?) # Maybe not delete password #TODO: ForumUserForm would delete children (need to generalize with realm_dag) # Need to generalize concept of parents so that we know a realm has # children and a parent. #TODO: when transitioning from unapproved to other state, send email # except unknown. Have code in place to transition, but the views # can be empty. map( _put_if_in_group($self, $main, @$_), [qw(file_writer all_admins)], [qw(mail_recipient all_members)], ); } foreach my $f (@{$self->internal_aux_fields}, 'mail_recipient') { if ($f eq 'is_subscribed') { _do_subscribed( $self, 'create_or_update', $uid, $self->unsafe_get($f)); } else { my($method) = $self->unsafe_get($f) ? 'create_or_update' : 'delete'; $ru->$method({ user_id => $uid, role => $_R->from_any($f), }); } } _audit_user($self, $uid); return; } sub internal_aux_fields { return [@$_AUX]; } sub internal_initialize { my($self) = @_; return $self->merge_initialize_info($self->SUPER::internal_initialize, { version => 1, require_context => 1, visible => [ { name => 'RealmUser.role', constraint => 'NOT_NULL', }, $self->field_decl( $self->internal_aux_fields, 'Boolean', ), ], other => [ 'RealmUser.user_id', $self->field_decl([[qw(current_main_role Auth.Role)]]), $self->field_decl([[qw(mail_recipient Boolean NOT_NULL)]]), ], }); } sub internal_pre_execute { my($self) = @_; unless ($self->unsafe_get('RealmUser.user_id')) { my($lm) = $self->new_other($self->USER_LIST_CLASS); $_FM->setup_by_list_this($lm, 'RealmOwner'); $self->internal_put_field( 'RealmUser.user_id' => $lm->get('RealmUser.user_id')); } # SECURITY: Limit privilege escalation to the level auth_user has my($auth_roles) = $self->req('auth_roles'); my($not_allowed) = [grep({ my($g) = $_; !grep($_->in_category_role_group($g), @$auth_roles); } qw(all_members all_admins everybody))]; $self->new_other('RoleSelectList')->load_from_array( [grep({ my($r) = $_; !$r->eq_unknown && !grep($r->in_category_role_group($_), @$not_allowed); } map($_R->from_any($_), @{$self->internal_select_roles}))], ); return shift->SUPER::internal_pre_execute(@_); } sub internal_select_roles { my($self) = @_; return $_F->get_from_source($self)->auth_realm_is_site_admin($self->req) ? [qw(WITHDRAWN USER MEMBER ADMINISTRATOR)] : [qw(UNKNOWN GUEST MEMBER ADMINISTRATOR)]; } sub validate { my($self) = @_; return if $self->in_error; return $self->internal_put_error('RealmUser.role' => 'NOT_FOUND') unless $self->req('Model.RoleSelectList') ->find_row_by('RealmUser.role' => $self->get('RealmUser.role')); return shift->SUPER::validate(@_); } sub _audit_user { my($self, $uid) = @_; $self->req->with_user($uid, sub { b_use('ShellUtil.RealmUser')->new->audit_user; }); return; } sub _do_subscribed { my($self, $method, $uid, $is_subscribed) = @_; return $self->new_other('UserRealmSubscription')->$method({ user_id => $uid, is_subscribed => $is_subscribed, }); } sub _put_if_in_group { my($self, $role, $field, $group) = @_; $self->internal_put_field($field => 1) if $role->in_category_role_group($group); return; } 1;