Line # Revision Author
1 196 ahitrov package users::UserProfile;
2
3 use base "Contenido::Document";
4 use Digest::MD5;
5 use Contenido::Globals;
6 325 ahitrov use Data::Dumper;
7 196 ahitrov
8 305 ahitrov my %CREDENTIAL_FIELDS = (
9 'users::Email' => 'email',
10 'users::Phone' => 'phone',
11 'users::OA::VK' => 'vkontakte',
12 'users::OA::FaceBook' => 'facebook',
13 'users::OA::Google' => 'google',
14 'users::OA::Mailru' => 'mailru',
15 );
16
17 310 ahitrov my %CREDENTIAL_REVERSE = (
18 'email' => 'users::Email',
19 'phone' => 'users::Phone',
20 'vkontakte' => 'users::OA::VK',
21 'facebook' => 'users::OA::FaceBook',
22 'google' => 'users::OA::Google',
23 'mailru' => 'users::OA::Mailru',
24 );
25
26 196 ahitrov sub extra_properties
27 {
28 return (
29 258 ahitrov { 'attr' => 'status', 'type' => 'status', 'rusname' => 'Статус пользователя',
30 196 ahitrov 'cases' => [
31 [0, 'Блокированный'],
32 [1, 'Активный'],
33 [5, 'Временная активация'],
34 ],
35 },
36 258 ahitrov { 'attr' => 'type', 'type' => 'status', 'rusname' => 'Тип аккаунта',
37 'cases' => [
38 [0, 'Обычный пользователь'],
39 [1, 'Продвинутый пользователь'],
40 [2, 'Модератор'],
41 [10, 'Администратор'],
42 ],
43 },
44 196 ahitrov { 'attr' => 'visibility', 'type' => 'status', 'rusname' => 'Область видимости',
45 'cases' => [
46 [0, 'Данные моего аккаунта видны только мне'],
47 [1, 'Данные моего аккаунта видны всем'],
48 [2, 'Данные моего аккаунта видны друзьям'],
49 [3, 'Данные моего аккаунта видны друзьям и членам клубов'],
50 ],
51 },
52 { 'attr' => 'country', 'type' => 'string', 'rusname' => 'Страна' },
53 { 'attr' => 'passwd', 'type' => 'password', 'rusname' => 'Пароль', 'rem' => '(<font color="red">Не отображается. Указывать при создании и для изменения</font>)' },
54 { 'attr' => 'confirm', 'type' => 'string', 'rusname' => 'Код подтверждения', hidden => 1 },
55 { 'attr' => 'secmail', 'type' => 'string', 'rusname' => 'E-mail (secondary)' },
56 { 'attr' => 'q1', 'type' => 'string', 'rusname' => 'Контрольный вопрос 1' },
57 { 'attr' => 'a1', 'type' => 'string', 'rusname' => 'Контрольный ответ 1' },
58 { 'attr' => 'q2', 'type' => 'string', 'rusname' => 'Контрольный вопрос 2' },
59 { 'attr' => 'a2', 'type' => 'string', 'rusname' => 'Контрольный ответ 2' },
60 { 'attr' => 'account', 'type' => 'string', 'rusname' => 'Сумма на счете' },
61 { 'attr' => 'interests', 'type' => 'text', 'rusname' => 'Жизненные интересы', rows => 10 },
62 { 'attr' => 'origin', 'type' => 'text', 'rusname' => 'Ориджин', rows => 4 },
63 258 ahitrov { 'attr' => 'avatar', 'type' => 'image', 'rusname' => 'Аватар', crop => ['32x32','150x150'], preview => ['200x200'] },
64 196 ahitrov )
65 }
66
67 305 ahitrov
68 sub post_init {
69 my $self = shift;
70 my $opts = shift;
71
72 $self->{passwd_prev} = $self->passwd;
73
74 return if exists $opts->{ids} || exists $opts{names} || exists $opts{light};
75 if ( $self->id && $state->{users}->use_credentials ) {
76 310 ahitrov $self->{credentials_available} = {};
77 305 ahitrov my $creds = $keeper->get_documents(
78 uid => $self->id,
79 table => 'users::SQL::CredentialsTable',
80 return_mode => 'array_ref',
81 );
82 if ( @$creds ) {
83 my %creds;
84 foreach my $cred ( @$creds ) {
85 $cred->{keeper} = undef;
86 my $main_field = $CREDENTIAL_FIELDS{$cred->class} if exists $CREDENTIAL_FIELDS{$cred->class};
87 310 ahitrov $self->{credentials_available}{$main_field} = 1;
88 305 ahitrov if ( $main_field ) {
89 my $multi_field = $main_field.'s';
90 $self->{$multi_field} = [] unless exists $self->{$multi_field};
91 push @{$self->{$multi_field}}, $cred;
92 $self->{$main_field} = $cred if $cred->main;
93 }
94 367 ahitrov if ( ref $self->{credentials_available} eq 'HASH' ) {
95 foreach my $main_field ( keys %{$self->{credentials_available}} ) {
96 my $multi_field = $main_field.'s';
97 unless ( $self->{$main_field} ) {
98 $self->{$main_field} = $self->{$multi_field}->[0];
99 }
100 }
101 }
102 305 ahitrov }
103 }
104 }
105 return;
106 }
107
108
109 238 ahitrov sub name_full
110 {
111 my $self = shift;
112 my $name = $self->name;
113 if ( $name =~ /^(.*?),[\ \t]+(.*)$/ ) {
114 $name = $2.' '.$1;
115 }
116 return $name;
117 }
118
119 sub name_part
120 {
121 my $self = shift;
122 my $name = $self->name;
123 if ( $name =~ /^(.*?),[\ \t]+(.*)$/ ) {
124 $name = $2;
125 414 ahitrov } else {
126 my @parts = split /\s+/, $name;
127 if ( @parts > 1 ) {
128 pop @parts;
129 }
130 $name = join ' ', @parts;
131 238 ahitrov }
132 return $name;
133 }
134
135 sub name_family
136 {
137 my $self = shift;
138 my $name = $self->name;
139 if ( $name =~ /^(.*?),[\ \t]+(.*)$/ ) {
140 $name = $1;
141 414 ahitrov } else {
142 my @parts = split /\s+/, $name;
143 if ( @parts > 1 ) {
144 $name = pop @parts;
145 }
146 238 ahitrov }
147 return $name;
148 }
149
150 414 ahitrov sub name_first
151 {
152 my $self = shift;
153 my @name = split /\s+/, $self->name_part;
154
155 return $name[0];
156 }
157
158 sub name_middle
159 {
160 my $self = shift;
161 my @name = split /\s+/, $self->name_part;
162 shift @name if @name;
163 my $name = @name ? join (' ', @name) : '';
164
165 return $name;
166 }
167
168 196 ahitrov sub class_name
169 {
170 return 'Профиль пользователя';
171 }
172
173 sub class_description
174 {
175 return 'Профиль пользователя';
176 }
177
178 sub search_fields
179 {
180 return ('email', 'name', 'login');
181 }
182
183 sub class_table
184 {
185 return 'users::SQL::UserProfile';
186 }
187
188 sub contenido_status_style
189 {
190 my $self = shift;
191 if ( $self->status == 2 ) {
192 return 'color:green;';
193 } elsif ( $self->status == 3 ) {
194 return 'color:olive;';
195 } elsif ( $self->status == 4 ) {
196 return 'color:green;';
197 } elsif ( $self->status == 5 ) {
198 return 'color:red;';
199 }
200 }
201
202 305 ahitrov
203 310 ahitrov sub get_credentials {
204 my ($self, $name, %opts) = @_;
205 my $objects;
206 if ( $name ) {
207 return undef unless exists $CREDENTIAL_REVERSE{$name};
208 my $names = $name.'s';
209 if ( exists $self->{credentials_available}{$name} ) {
210 $objects = $self->{$names};
211 }
212 } elsif ( my @keys = keys %{$self->{credentials_available}} ) {
213 $objects = {};
214 foreach my $key ( @keys ) {
215 my $names = $key.'s';
216 311 ahitrov push @{$objects->{$key}}, $self->{$names};
217 310 ahitrov }
218 }
219 return $objects;
220 }
221
222 305 ahitrov sub confirm_credential {
223 my ($self, %opts) = @_;
224 379 ahitrov return undef unless $self->id;
225 305 ahitrov my $object;
226 if ( exists $opts{confirm} && $opts{name} && $opts{class} ) {
227 ($object) = $self->keeper->get_documents(
228 class => $opts{class},
229 uid => $self->id,
230 name => lc($opts{name}),
231 limit => 1,
232 );
233 if ( ref $object && $object->confirm eq $opts{confirm} ) {
234 $object->status(1);
235 $object->store;
236 }
237 } elsif ( $opts{name} && $opts{class} ) {
238 ($object) = $self->keeper->get_documents(
239 class => $opts{class},
240 uid => $self->id,
241 name => lc($opts{name}),
242 limit => 1,
243 );
244 if ( ref $object ) {
245 $object->status(1);
246 $object->store;
247 }
248 }
249 379 ahitrov if ( ref $object && ($object->class eq 'users::Phone' || $object->class eq 'users::Email') && $object->main && $self->status == 5 ) {
250 $self->status(1);
251 $self->store;
252 }
253 305 ahitrov return $object;
254 }
255
256
257 sub create_credential {
258 my ($self, %opts) = @_;
259 my $object;
260 if ( $opts{vkontakte} ) {
261 ($object) = $self->keeper->get_documents(
262 306 ahitrov class => 'users::OA::VK',
263 305 ahitrov ext_id => $opts{vkontakte},
264 limit => 1,
265 );
266 310 ahitrov return undef if ref $object && $object->uid != $self->id;
267 305 ahitrov unless ( ref $object ) {
268 $object = users::OA::VK->new ($keeper);
269 $object->name( $opts{name} );
270 314 ahitrov $object->ext_id( $opts{vkontakte} );
271 305 ahitrov $object->status( 1 );
272 $object->opaque( $opts{opaque} || 0 );
273 $object->uid( $self->id );
274 $object->ava_url( $opts{avatar} );
275 $object->store;
276 }
277 } elsif ( $opts{facebook} ) {
278 ($object) = $self->keeper->get_documents(
279 306 ahitrov class => 'users::OA::FaceBook',
280 305 ahitrov ext_id => $opts{facebook},
281 limit => 1,
282 );
283 310 ahitrov return undef if ref $object && $object->uid != $self->id;
284 305 ahitrov unless ( ref $object ) {
285 $object = users::OA::FaceBook->new ($keeper);
286 $object->name( $opts{name} );
287 314 ahitrov $object->ext_id( $opts{facebook} );
288 305 ahitrov $object->status( 1 );
289 $object->opaque( $opts{opaque} || 0 );
290 $object->uid( $self->id );
291 $object->ava_url( $opts{avatar} );
292 $object->store;
293 }
294 } elsif ( $opts{google} ) {
295 ($object) = $self->keeper->get_documents(
296 306 ahitrov class => 'users::OA::Google',
297 305 ahitrov ext_id => $opts{google},
298 limit => 1,
299 );
300 310 ahitrov return undef if ref $object && $object->uid != $self->id;
301 305 ahitrov unless ( ref $object ) {
302 $object = users::OA::Google->new ($keeper);
303 $object->name( $opts{name} );
304 314 ahitrov $object->ext_id( $opts{google} );
305 305 ahitrov if ( $opts{email} ) {
306 $object->email( $opts{email} );
307 $self->create_credential( email => $opts{email}, status => 1 );
308 }
309 $object->status( 1 );
310 $object->opaque( $opts{opaque} || 0 );
311 $object->uid( $self->id );
312 $object->ava_url( $opts{avatar} );
313 $object->store;
314 }
315 } elsif ( $opts{mailru} ) {
316 ($object) = $self->keeper->get_documents(
317 306 ahitrov class => 'users::OA::Mailru',
318 305 ahitrov ext_id => $opts{mailru},
319 limit => 1,
320 );
321 310 ahitrov return undef if ref $object && $object->uid != $self->id;
322 305 ahitrov unless ( ref $object ) {
323 $object = users::OA::Mailru->new ($keeper);
324 $object->name( $opts{name} );
325 314 ahitrov $object->ext_id( $opts{mailru} );
326 305 ahitrov if ( $opts{email} ) {
327 $object->email( $opts{email} );
328 $self->create_credential( email => $opts{email}, status => 1 );
329 }
330 $object->status( 1 );
331 $object->opaque( $opts{opaque} || 0 );
332 $object->uid( $self->id );
333 $object->ava_url( $opts{avatar} );
334 $object->store;
335 }
336 } elsif ( $opts{email} ) {
337 ($object) = $self->keeper->get_documents(
338 306 ahitrov class => 'users::Email',
339 305 ahitrov name => lc($opts{email}),
340 limit => 1,
341 );
342 310 ahitrov return undef if ref $object && $object->uid != $self->id;
343 305 ahitrov unless ( ref $object ) {
344 $object = users::Email->new ($keeper);
345 $object->name( lc($opts{email}) );
346 $object->name_orig( $opts{email} );
347 $object->main( $opts{main} || 0 );
348 $object->status( $opts{status} || 0 );
349 $object->opaque( $opts{opaque} || 0 );
350 $object->uid( $self->id );
351 $object->confirm( Digest::MD5::md5_hex(int(rand(1000000)), $self->id, $opts{email}) );
352 $object->store;
353 373 ahitrov } else {
354 if ( exists $opts{status} && $object->status != $opts{status} ) {
355 $object->status( $opts{status} );
356 $object->store;
357 }
358 305 ahitrov }
359 420 ahitrov if ( ref $object && $object->id ) {
360 $self->{phones} = [] unless exists $self->{phones};
361 if ( $opts{main} ) {
362 my $sql = $keeper->SQL->prepare('update profile_credentials set main = 0 where class = ? and uid = ? and id != ?');
363 $sql->execute( $object->class, $self->id, $object->id );
364 $sql->finish;
365 $self->{email} = $object;
366 unshift @{$self->{emails}}, $object;
367 } else {
368 push @{$self->{emails}}, $object;
369 }
370 }
371 373 ahitrov if ( $opts{main} ) {
372 }
373 305 ahitrov } elsif ( $opts{phone} ) {
374 ($object) = $self->keeper->get_documents(
375 306 ahitrov class => 'users::Phone',
376 305 ahitrov name => $keeper->{users}->_phone_reduction( $opts{phone} ),
377 limit => 1,
378 );
379 310 ahitrov return undef if ref $object && $object->uid != $self->id;
380 305 ahitrov unless ( ref $object ) {
381 $object = users::Phone->new ($keeper);
382 $object->name( $keeper->{users}->_phone_reduction($opts{phone}) );
383 $object->name_format( $keeper->{users}->_phone_format($opts{phone}) );
384 $object->name_orig( $opts{phone} );
385 $object->main( $opts{main} || 0 );
386 $object->status( $opts{status} || 0 );
387 $object->opaque( $opts{opaque} || 0 );
388 $object->uid( $self->id );
389 $object->confirm( Digest::MD5::md5_hex(int(rand(1000000)), $self->id, $opts{email}) );
390 $object->store;
391 373 ahitrov } else {
392 if ( exists $opts{status} && $object->status != $opts{status} ) {
393 $object->status( $opts{status} );
394 $object->store;
395 }
396 305 ahitrov }
397 420 ahitrov if ( ref $object && $object->id ) {
398 $self->{phones} = [] unless exists $self->{phones};
399 if ( $opts{main} ) {
400 my $sql = $keeper->SQL->prepare('update profile_credentials set main = 0 where class = ? and uid = ? and id != ?');
401 $sql->execute( $object->class, $self->id, $object->id );
402 $sql->finish;
403 $self->{phone} = $object;
404 unshift @{$self->{phones}}, $object;
405 } else {
406 push @{$self->{phones}}, $object;
407 }
408 373 ahitrov }
409 305 ahitrov }
410 return $object;
411 }
412
413
414 339 ahitrov sub table_links
415 {
416 my $self = shift;
417 my @links;
418 if ( $state->{users}->use_credentials ) {
419 @links = (
420 { name => 'E-mail', class => 'users::Email', filter => 'uid', field => 'uid' },
421 { name => 'Phone', class => 'users::Phone', filter => 'uid', field => 'uid' },
422 515 ahitrov { name => 'Socials', class => ['users::OA::FaceBook','users::OA::VK'], filter => 'uid', field => 'uid' },
423 339 ahitrov );
424 }
425 return \@links;
426 }
427
428 196 ahitrov sub pre_store
429 {
430 my $self = shift;
431
432 305 ahitrov my $passwd_prev = $self->{passwd_prev} || '';
433 if ( $self->passwd && $self->passwd ne $passwd_prev ) {
434 196 ahitrov warn "Pass = ".$self->passwd."\n" if $DEBUG;
435 my $pass = Digest::MD5::md5_hex($self->passwd);
436 warn "Pass_hex = $pass\n" if $DEBUG;
437 $self->passwd($pass);
438 305 ahitrov } else {
439 $self->passwd($passwd_prev);
440 196 ahitrov }
441 305 ahitrov $self->login( lc($self->login) );
442 196 ahitrov
443 305 ahitrov if ( $state->{users}->use_credentials ) {
444 foreach my $prop ( $self->structure ) {
445 my $name = $prop->{attr};
446 325 ahitrov if ( ref($self->{$name}) =~ /^users\:\:OA\:\:/ ) {
447 315 ahitrov my $obj = $self->{$name};
448 321 ahitrov $self->{$name} = $obj->ext_id;
449 325 ahitrov } elsif ( ref($self->{$name}) =~ /^users\:\:/ ) {
450 315 ahitrov my $obj = $self->{$name};
451 321 ahitrov $self->{$name} = $obj->name;
452 305 ahitrov }
453 }
454 } else {
455 $self->email( $keeper->{users}->_email_reduction($self->email) );
456 }
457
458 196 ahitrov my $default_section = $project->s_alias->{users} if ref $project->s_alias eq 'HASH' && exists $project->s_alias->{users};
459 if ( $default_section ) {
460 my $sections = $self->{sections};
461 if ( ref $sections eq 'ARRAY' && scalar @$sections ) {
462 my @new_sects = grep { $_ != $default_section } @$sections;
463 push @new_sects, $default_section;
464 $self->sections(@new_sects);
465 } elsif ( $sections && !ref $sections && $sections != $default_section ) {
466 my @new_sects = ($default_section, $sections);
467 $self->sections(@new_sects);
468 } else {
469 $self->sections($default_section);
470 }
471 }
472 return 1;
473 }
474 310 ahitrov
475
476 379 ahitrov sub post_store
477 {
478 my $self = shift;
479
480 if ( $state->{users}->use_credentials && $self->email ) {
481 420 ahitrov my $object = $self->create_credential( email => $self->email, main => 1, $self->status == 1 ? (status => 1) : () );
482 if ( ref $object && $object->id ) {
483 $self->{email} = $object;
484 $self->{emails} = [] unless exists $self->{emails};
485 unshift @{$self->{emails}}, $object;
486 }
487 379 ahitrov }
488
489 1;
490 }
491
492
493 310 ahitrov sub post_delete
494 {
495 my $self = shift;
496
497 if ( $state->{users}->use_credentials ) {
498 my $creds = $keeper->get_documents(
499 table => 'users::SQL::CredentialsTable',
500 uid => $self->id,
501 return_mode => 'array_ref',
502 );
503 map { $_->delete( attachments => 1 ) } @$creds;
504 }
505 1;
506 }
507
508 196 ahitrov 1;