package Slovo::Controller::Users; use Mojo::Base 'Slovo::Controller', -signatures; # GET /users/create # Display form for creating resource in table users. sub create ($c) { return $c->render(users => {}, user => $c->user); } # POST /users # Add a new record to table users. sub store ($c) { my $users = $c->users; if ($c->current_route =~ /^api\./) { #invoked via OpenAPI $c->openapi->valid_input or return; my $in = $c->validation->output; my $id = $users->add($in); $c->res->headers->location($c->url_for("api.show_users", id => $id)->to_string); return $c->render(openapi => '', status => 201); } # 1. Validate input my $v = $c->_validation; #TODO: FIX: implement proper validation error handling return $c->render(action => 'create', users => {}) if $v->has_error; my $in = $v->output; $in->{created_by} = $in->{changed_by} = $c->user->{id}; $in->{reg_time} = time - 1; $in->{start_date} //= time - 1; $in->{disabled} //= 0; $in->{stop_date} = 0; # 1.1 Check if user already exists my $u = $users->find_where([{login_name => $in->{login_name}}, {email => $in->{email}}]); if ($u) { my @data = (); if ($u->{login_name} eq $in->{login_name}) { push @data, $u->{login_name}; } if ($u->{email} eq $in->{email}) { push @data, $u->{email}; } $c->flash(message => 'Потребител със същите данни (' . join(', ', @data) . ') вече съществува.'); return $c->redirect_to('create_users'); } # 2. Insert it into the database my $id = $users->add($in); #3. redirect if ($INC{'Slovo/Task/SendOnboardingEmail.pm'}) { # send email from the current user to the new user to login for the first # time and change his password. my $job_id = $c->minion->enqueue(mail_first_login => [{%{$c->user}} => {%{$users->find_where({id => $id})}}, $c->req->headers->host]); return $c->redirect_to('users_store_result', jid => $job_id); } return $c->redirect_to('home_users'); } # GET /users/store_result/:jid sub store_result ($c) { return $c->reply->not_found unless my $job = $c->minion->job($c->param('jid')); return $c->render(job => $job); } # GET /users/:id/edit # Display form for edititing resource in table users. sub edit ($c) { my $row = $c->users->find_where({id => $c->param('id')}); for (keys %$row) { $c->req->param($_ => $row->{$_}); # prefill form fields. } return $c->render(users => $row, user => $c->user); } # PUT /users/:id # Update the record in table users sub update ($c) { # Validate input my $v = $c->_validation; my $in = $v->output; my $id = $c->param('id'); return $c->render(action => 'edit', users => $in) if $v->has_error; # only admins can edit groups delete $in->{groups} unless ($c->groups->is_admin($c->user->{id})); # Update the record $in->{changed_by} = $c->user->{id}; $in->{tstamp} = time - 1; $c->users->save($id, $in); return $c->redirect_to('show_users', id => $id); # Redirect to the updated record or just send "204 No Content" # See https://developer.mozilla.org/docs/Web/HTTP/Status/204 # $c->res->headers->location($c->url_for(show_users => {id => $id})); # return $c->render(text => '', status => 204); } # GET /users/:id # Display a record from table users. sub show ($c) { my $row = $c->users->find_where({id => $c->param('id')}); if ($c->current_route =~ /^api\./) { #invoked via OpenAPI return $c->render( openapi => {errors => [{path => $c->url_for, message => 'Not Found'}]}, status => 404 ) unless $row; return $c->render(openapi => $row); } return $c->render(text => $c->res->default_message(404), status => 404) unless $row; return $c->render(users => $row); } # GET /users # List resources from table users. ## no critic qw(Subroutines::ProhibitBuiltinHomonyms) sub index ($c) { my $stashkey = 'users'; if ($c->current_route =~ /^api\./) { #invoked via OpenAPI $c->openapi->valid_input or return; $stashkey = 'openapi'; } my $users = $c->users->all({where => {disabled => {-in => [0, 1]}}}); return $c->render($stashkey => $users, user => $c->user); } # DELETE /users/:id sub remove ($c) { if ($c->current_route =~ /^api\./) { #invoked via OpenAPI $c->openapi->valid_input or return; my $input = $c->validation->output; my $row = $c->users->find($input->{id}); $c->render( openapi => {errors => [{path => $c->url_for, message => 'Not Found'}]}, status => 404 ) && return unless $row; $c->users->remove($input->{id}); return $c->render(openapi => '', status => 204); } $c->users->remove($c->param('id')); return $c->redirect_to('home_users'); } # Validation for actions that store or update sub _validation ($c) { my $v = $c->validation; my $mail_rx = qr/^[\w\-\+\.]{1,154}\@[\w\-\+\.]{1,100}$/x; # Add validation rules for the record to be stored in the database $v->optional('group_id', 'trim')->like(qr/^\d+$/); $v->optional('login_name', 'trim')->like(qr/^[\p{IsAlnum}\.\-\$]{3,12}$/x); if ($c->stash->{action} eq 'store') { $v->required('login_password', 'trim')->like(qr/^[A-F0-9]{40}$/i); $v->required('first_name', 'trim')->size(2, 100); $v->required('last_name', 'trim')->size(2, 100); $v->required('email', 'trim')->like($mail_rx); } else { $v->optional('login_password', 'trim')->like(qr/^[A-F0-9]{40}$/i); $v->optional('first_name', 'trim')->size(2, 100); $v->optional('last_name', 'trim')->size(2, 100); $v->optional('email', 'trim')->like($mail_rx); $v->optional('id', 'trim')->like(qr/^\d+$/); my $groups = $c->groups->all_with_member($c->stash('id'))->map(sub { $_->{id} }); $v->optional('groups')->in(@$groups); } $v->optional('description', 'trim')->size(0, 255); $v->optional('disabled', 'trim')->like(qr/^[01]$/); my $time_qr = qr/^\d{1,10}$/; $v->optional('start_date', 'trim')->like($time_qr); $v->optional('stop_date', 'trim')->like($time_qr); return $v; } 1;