1 package Newslash::Plugin::Users;
2 use Mojo::Base 'Mojolicious::Plugin';
10 my ($self, $app, $conf) = @_;
12 $app->helper(users => sub { state $users = $self; });
14 # default config values
15 my $cnf = $app->config->{Users} ||= {};
16 $cnf->{newpasswd_expiration} ||= 60 * 60 * 24; # 60[sec] * 60[min] * 24[hour]
20 my ($self, $user, $email) = @_;
22 if (!$user || !$user->{uid}) {
23 $self->last_error("INVALID_USER");
27 if (!$email || !Email::Valid->address($email)) {
28 $self->last_error("INVALID_EMAIL");
32 # use users_param table to save temporary new email address
34 my $users = $self->app->model('users');
35 my $param = $users->param;
37 my $rs = $param->set(uid => $user->{uid},
42 $self->app->error("Users: update users_param table for change_email failed! uid: $user->{uid}");
43 $self->last_error($param->last_error);
47 $self->app->event_que->emit("user", "change_email", $user->{uid}, $user->{uid}, 10);
52 my ($self, $user) = @_;
54 if (!$user || $user->{uid}) {
55 $self->last_error("INVALID_USER");
59 $self->app->event_que->emit("user", "reset_password", $user->{uid}, $user->{uid}, 10);
63 sub cancel_activation {
64 my ($self, $user) = @_;
65 if (!$user || $user->{uid}) {
66 $self->last_error("INVALID_USER");
70 my $users = $self->app->model('users');
72 my $rs = $users->update(uid => $user->{uid},
74 newpasswd_ts => {function => "NULL"});
76 $self->app->log->error("Users: newpasswd reset error! uid: $user->{uid}");
77 $self->last_error($users->last_error);
83 sub update_password_by_token {
84 my ($self, $nickname, $token, $password) = @_;
86 # check nickname and token pair
87 my $user = $self->activation($nickname, $token);
90 return $self->_update_password($user, $password);
94 my ($self, $user, $old_password, $new_password) = @_;
95 if (!$user || !$user->{uid}) {
96 $self->last_error("INVALID_USER");
100 my $users = $self->app->model('users');
102 if ($users->passwords->verify_password(uid => $user->{uid},
103 password => $old_password)) {
104 # old password is correct.
105 return $self->_update_password($user, $new_password);
108 # old password is incorrect!
109 $self->last_error("INCORRECT_PASSWORD");
113 sub _update_password {
114 my ($self, $user, $password) = @_;
116 if (!$user || !$user->{uid}) {
117 $self->last_error("INVALID_USER");
121 my $users = $self->app->model('users');
123 my @params = (uid => $user->{uid},
124 passwd => $password );
126 if ($user->{seclev} < 1) {
127 push @params, seclev => 1;
130 if ($user->{newpasswd}) {
131 push @params, newpasswd => "";
132 push @params, newpasswd_ts => { function => "NULL" };
135 my $rs = $users->update(@params);
138 $self->last_error($users->last_error);
141 $self->app->event_que->emit("user", "update_password", $user->{uid}, $user->{uid}, 10);
147 my ($self, $nickname, $token) = @_;
148 return if (!$nickname || !$token);
150 my $users = $self->app->model('users');
151 my $user = $users->select(nickname => $nickname);
153 # check if token is correct
155 || !$users->passwords->compare_password($token, $user->{newpasswd})
156 || !$user->{newpasswd_ts}) {
157 $self->last_error("INVALID_TOKEN");
161 # check if token is expired
162 my $expiration_limit = $self->app->config->{Users}->{newpasswd_expiration};
163 my $expire_dt = eval { DateTime::Format::MySQL->parse_datetime($user->{newpasswd_ts}) };
165 $self->app->log->error("Users: invalid newpasswd_ts ($user->{newpasswd_ts}). uid: $user->{uid}");
166 $self->last_error("INVALID_TOKEN");
169 $expire_dt->add( seconds => $expiration_limit);
170 if ($expire_dt->epoch() < time()) {
171 $self->last_error("TOKEN_EXPIRED");
179 sub create_new_user {
180 my ($self, $nickname, $email, $options) = @_;
181 my $users = $self->app->model('users');
184 # check $nickname and $email
185 my ($id_error, $email_error) = $self->validate_new_user($nickname, $email);
186 if ($id_error || $email_error) {
187 $self->last_error({ id_error => $id_error,
188 email_error => $email_error });
192 my $uid = $users->create($nickname, $email, "", { seclev => 0 });
195 $self->last_error({ id_error => $id_error,
196 email_error => $email_error,
197 system_error => $users->last_error });
202 if ($options->{message}) {
203 my $message_types = $self->app->model('messages');
204 for my $k (keys %{$options->{message}}) {
205 my $rs = $users->messages->update(uid => $uid,
207 mode => $options->{message}->{$k});
209 $self->app->log->error("Users: message update failed! uid: $uid, name: $k, mode: $options->{message}->{$k}");
214 $self->app->event_que->emit("user", "create", $uid, $uid, 10);
218 sub validate_new_user {
219 my ($self, $nickname, $email) = @_;
220 my $nick_regex = qr/^[a-zA-Z_][ a-zA-Z0-9\$_.+!*\'(),-]{0,19}$/;
221 my $users = $self->app->model('users');
223 my ($id_error, $email_error);
224 $id_error = "BLANK_ID" if !$nickname;
225 $email_error = "BLANK_EMAIL" if !$email;
229 if ($nickname =~ $nick_regex) {
230 my $matchname = $users->nickname_to_matchname($nickname);
231 my $rs = $users->select(matchname => $matchname);
233 $id_error = "ID_EXISTS";
237 $id_error = "INVALID_ID";
242 if (Email::Valid->address($email)) {
243 my $rs = $users->select(realemail => $email);
245 $email_error = "EMAIL_EXISTS";
249 $email_error = "INVALID_EMAIL";
253 if ($id_error || $email_error) {
254 $self->last_error({id_error => $id_error, email_error => $email_error});
267 Newslash::Plugin::Users - Newslash users manipulation plugin
272 $app->plugin('Newslash::Plugin::Users');
276 L<Newslash::Plugin::Users> is 'Business Logic' layer of Newslash.
281 L<Mojolicious::Plugin::Users> implements the following helpers.
285 [% helpers.boxes() %]
287 Fetch box contents for current user and returns them.
289 =head2 format_timestamp
291 $c->format_timestamp(user => $user, epoch => $epoch, format => "user")
292 $c->format_timestamp(datetime => $dt, format => "simple")
294 Return formated string.
300 $plugin->register(Mojolicious->new);
302 Register helpers in L<Mojolicious> application.
304 =head2 validate_new_user
306 my ($id_error, $email_error) = $plugin->validate_new_user($nickname, $email);
308 Check nickname and email address are not registered.
310 $id_error is one of below string or undef (no error).
316 $email_error is one of below string or undef (no error).
325 L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicious.org>.