Revision 305
Date:
2013/04/22 16:42:50
Author:
ahitrov
Revision Log:
Credentials
Files:
Legend:
Added
Removed
Modified
utf8/plugins/users/config.proto
18
18
PROFILE_AUTH_METHOD = RPC
19
19
REWRITE += PROFILE_AUTH_METHOD
20
20
21
21
PROFILE_USE_CREDENTIALS = <YES/NO>
22
REWRITE += PROFILE_USE_CREDENTIALS
22
23
########################################################################
23
24
#
24
25
# PROFILE_DOCUMENT_CLASS
utf8/plugins/users/lib/users/Email.pm
1
package users::Email;
2
3
use base "Contenido::Document";
4
use Contenido::Globals;
5
6
use overload (
7
'""' => '_stringify',
8
);
9
10
sub extra_properties
11
{
12
return (
13
{ 'attr' => 'name', 'type' => 'string', 'rusname' => 'E-mail' },
14
{ 'attr' => 'status', 'type' => 'status', 'rusname' => 'Статус e-mail-адреса',
15
'cases' => [
16
[0, 'Не активен'],
17
[1, 'Подтвержден'],
18
[2, 'Основной'],
19
[3, 'Потерян / заблокирован'],
20
],
21
},
22
{ 'attr' => 'name_orig', 'type' => 'string', 'rusname' => 'E-mail без приведения к нижнему регистру' },
23
# { 'attr' => 'login', 'type' => 'string', 'rusname' => 'Login' },
24
# { 'attr' => 'passwd', 'type' => 'string', 'rusname' => 'Password' },
25
)
26
}
27
28
sub _stringify {
29
my $self = shift;
30
31
return $self->name;
32
}
33
34
35
sub class_name
36
{
37
return 'E-mail адрес';
38
}
39
40
sub class_description
41
{
42
return 'E-mail адрес';
43
}
44
45
sub search_fields
46
{
47
return ('name');
48
}
49
50
sub class_table
51
{
52
return 'users::SQL::CredentialsTable';
53
}
54
55
sub contenido_status_style
56
{
57
my $self = shift;
58
if ( $self->status == 2 ) {
59
return 'color:green;';
60
} elsif ( $self->status == 3 ) {
61
return 'color:red;';
62
}
63
}
64
65
sub pre_store
66
{
67
my $self = shift;
68
69
my $default_section = $project->s_alias->{user_emails} if ref $project->s_alias eq 'HASH' && exists $project->s_alias->{user_emails};
70
if ( $default_section && !$self->{sections} ) {
71
$self->{sections} = $default_section;
72
}
73
74
return 1;
75
}
76
1;
utf8/plugins/users/lib/users/Init.pm
13
13
# users::SomeClass
14
14
Contenido::Init::load_classes(qw(
15
15
users::SQL::UserProfile
16
users::SQL::CredentialsTable
16
17
17
18
users::UserProfile
19
users::Email
20
users::Phone
18
21
users::Section
22
23
users::OA::VK
24
users::OA::FaceBook
25
users::OA::Google
26
users::OA::Mailru
19
27
));
20
28
21
29
sub init {
22
30
push @{ $state->{'available_documents'} }, 'users::UserProfile' if $state->{users}->profile_document_class eq 'users::UserProfile';
23
31
push @{ $state->{'available_sections'} }, 'users::Section';
32
if ( $state->{users}->use_credentials ) {
33
push @{ $state->{'available_documents'} },
34
qw( users::Email users::Phone users::OA::VK users::OA::FaceBook users::OA::Google users::OA::Mailru );
35
}
24
36
0;
25
37
}
26
38
utf8/plugins/users/lib/users/Keeper.pm
39
39
#
40
40
# login => login пользователя
41
41
# email => e-mail пользователя
42
# phone => телефон пользователя
42
43
# passwd => пароль пользователя
43
44
# ----------------------------------------------------------------------------
44
45
sub login {
45
46
46
my $self = shift;
47
my %opts = @_;
47
my $self = shift;
48
my (%opts) = @_;
48
49
49
return if !($opts{login} || $opts{email}) && !$opts{passwd};
50
my $passmd5 = Digest::MD5::md5_hex($opts{passwd});
51
my $class = $self->state->profile_document_class;
52
my $res = $keeper->get_documents (
53
class => $class,
54
$opts{login} ? (login => $opts{login}) : (),
55
$opts{email} ? (email => lc($opts{email})) : (),
56
status => [1,2,3,4,5],
57
return_mode => 'array_ref',
58
);
59
$res = ref $res eq 'ARRAY' ? $res->[0] : undef;
60
return unless ref $res;
61
# warn "Password = ".$opts{passwd}."; Pass MD5 = $passmd5; user MD5 = ".$res->passwd."\n" if $DEBUG;
62
if ($res->passwd eq $passmd5 ) {
63
my $lastlogin = Contenido::DateTime->new ( postgres => $res->lastlogin );
64
my $now = Contenido::DateTime->new;
65
my $then = $now->clone;
66
$then->subtract( hours => 2 );
67
if ( DateTime->compare($then, $lastlogin) == 1 ) {
68
$res->lastlogin( $now->ymd('-').' '.$now->hms );
69
$res->passwd(undef);
70
$res->store;
71
$res->lastlogin( $lastlogin->ymd('-').' '.$lastlogin->hms );
50
return if !($opts{login} || $opts{email} || $opts{phone}) && !$opts{passwd};
51
52
my $password = delete $opts{passwd};
53
my $passmd5 = Digest::MD5::md5_hex( $password );
54
my $class = $self->state->profile_document_class;
55
my $profile = $self->get_profile( %opts, status => [qw(1 2 3 4 5)] );
56
return unless ref $profile;
57
58
my $result;
59
# warn "Password = ".$opts{passwd}."; Pass MD5 = $passmd5; user MD5 = ".$res->passwd."\n" if $DEBUG;
60
if ($profile->passwd eq $passmd5 ) {
61
my ($prop) = grep { $_->{attr} eq 'lastlogin' } $profile->structure;
62
if ( ref $prop ) {
63
my $now = Contenido::DateTime->new;
64
$profile->lastlogin( $now->ymd('-').' '.$now->hms );
65
$profile->store;
72
66
}
73
return $res;
74
}else{
75
return;
76
}
77
67
return $profile;
68
} else {
69
return undef;
70
}
78
71
}
79
72
80
73
…
…
125
118
# email => по e-mail
126
119
# nickname=> по никнейму
127
120
# status => фильтр по статусу
121
# При включенных credentials:
122
# phone => по телефону
123
# vkontakte => по логину ВК
124
# facebook => по логину Facebook
125
# google => по логину Google
126
# mailru => по логину Mail.ru
128
127
# ----------------------------------------------------------------------------
129
128
sub get_profile {
130
129
131
my $self = shift;
132
my %opts = @_;
130
my $self = shift;
131
my (%opts) = @_;
133
132
134
return if !$opts{login} && !$opts{id} && !$opts{email} && !$opts{nickname};
135
my $class = $self->state->profile_document_class;
136
my $res = $keeper->get_documents (
133
my $profile;
134
if ( $self->state->use_credentials && !$opts{login} && !$opts{id} ) {
135
$profile = $self->get_profile_by_credential ( %opts );
136
} else {
137
return if !$opts{login} && !$opts{id} && !$opts{email} && !$opts{nickname};
138
my $class = $self->state->profile_document_class;
139
($profile) = $keeper->get_documents (
140
class => $class,
141
%opts,
142
limit => 1,
143
);
144
}
145
return $profile;
146
}
147
148
149
sub get_profile_by_credential {
150
151
my $self = shift;
152
my (%opts) = @_;
153
154
my $credential;
155
if ( $opts{email} && $self->_email_format($opts{email}) ) {
156
($credential) = $keeper->get_documents (
157
class => 'users::Email',
158
name => $self->_email_reduction( delete $opts{email} ),
159
limit => 1,
160
);
161
} elsif ( $opts{phone} && $self->_phone_reduction($opts{phone}) ) {
162
($credential) = $keeper->get_documents (
163
class => 'users::Phone',
164
name => $self->_phone_reduction( delete $opts{phone} ),
165
limit => 1,
166
);
167
} elsif ( $opts{vkontake} ) {
168
($credential) = $keeper->get_documents (
169
class => 'users::OA::VK',
170
ext_id => delete $opts{vkontakte},
171
limit => 1,
172
);
173
} elsif ( $opts{facebook} ) {
174
($credential) = $keeper->get_documents (
175
class => 'users::OA::FaceBook',
176
ext_id => delete $opts{facebook},
177
limit => 1,
178
);
179
} elsif ( $opts{mailru} ) {
180
($credential) = $keeper->get_documents (
181
class => 'users::OA::Mailru',
182
ext_id => delete $opts{mailru},
183
limit => 1,
184
);
185
} elsif ( $opts{google} ) {
186
($credential) = $keeper->get_documents (
187
class => 'users::OA::Google',
188
ext_id => delete $opts{google},
189
limit => 1,
190
);
191
}
192
return unless ref $credential;
193
194
my $class = $self->state->profile_document_class;
195
my $profile = $keeper->get_document_by_id ( $credential->uid,
137
196
class => $class,
138
197
%opts,
139
return_mode => 'array_ref',
140
198
);
141
$res = ref $res eq 'ARRAY' && scalar @$res ? $res->[0] : undef;
142
return $res;
199
return $profile;
143
200
}
144
201
202
203
###### Additional subs
204
###################################################
205
sub _email_format {
206
my $self = shift;
207
my $email = shift;
208
for ( $email ) {
209
s/^\s+//;
210
s/\s+$//;
211
}
212
if ( $email =~ /^[\-\.\w\d]+\@[a-z\d\-\.]+\.[a-z\d]+$/i ) {
213
return $email;
214
}
215
return undef;
216
}
217
218
sub _email_reduction {
219
my $self = shift;
220
my $email = shift;
221
for ( $email ) {
222
s/^\s+//;
223
s/\s+$//;
224
}
225
if ( $email =~ /^[\-\.\w\d]+\@[a-z\d\-\.]+\.[a-z\d]+$/i ) {
226
return lc( $email );
227
}
228
return undef;
229
}
230
231
sub _phone_format {
232
my $self = shift;
233
my $phone = shift;
234
if ( $phone ) {
235
for ( $phone ) {
236
s/-//g;
237
s/\[/\(/g;
238
s/\]/\)/g;
239
s/^\s+//;
240
s/\s+$//;
241
}
242
if ( $phone =~ /^\+?(\d)+[\(\ ]+(\d+)[\)\ ]+([\d+\ ])$/ ) {
243
my $cc = $1;
244
my $code = $2;
245
my $number = $3; $number =~ s/\D//g;
246
$phone = $cc.'('.$code.')'.$phone;
247
} elsif ( $phone =~ /^[\(]+(\d+)[\)\ ]+([\d+\ ])$/ ) {
248
my $cc = '7';
249
my $code = $1;
250
my $number = $2; $number =~ s/\D//g;
251
$phone = $cc.'('.$code.')'.$phone;
252
} else {
253
$phone =~ s/\D//g;
254
}
255
return $phone;
256
}
257
}
258
259
sub _phone_reduction {
260
my $self = shift;
261
my $phone = shift;
262
if ( $phone ) {
263
$phone =~ s/\D//g;
264
return $phone || undef;
265
}
266
}
267
145
268
1;
utf8/plugins/users/lib/users/OA/Credential.pm
1
package users::OA::Credential;
2
3
use base "Contenido::Document";
4
use Contenido::Globals;
5
6
sub extra_properties
7
{
8
return (
9
{ 'attr' => 'name', 'type' => 'string', 'rusname' => 'Имя в системе' },
10
{ 'attr' => 'status', 'type' => 'status', 'rusname' => 'Статус',
11
'cases' => [
12
[0, 'Не активен'],
13
[1, 'Подтвержден'],
14
[3, 'Потерян / заблокирован'],
15
],
16
},
17
{ 'attr' => 'ava_url', 'type' => 'url', 'rusname' => 'Аватар (url)' },
18
{ 'attr' => 'avatar', 'type' => 'image', 'rusname' => 'Аватар' },
19
# { 'attr' => 'login', 'type' => 'string', 'rusname' => 'Login' },
20
# { 'attr' => 'passwd', 'type' => 'string', 'rusname' => 'Password' },
21
)
22
}
23
24
sub class_name
25
{
26
return 'OpenAuth Proto';
27
}
28
29
sub class_description
30
{
31
return 'OpenAuth Proto class';
32
}
33
34
sub search_fields
35
{
36
return ('ext_id', 'name', 'uid');
37
}
38
39
sub class_table
40
{
41
return 'users::SQL::CredentialsTable';
42
}
43
44
sub contenido_status_style
45
{
46
my $self = shift;
47
if ( $self->status == 3 ) {
48
return 'color:red;';
49
}
50
}
51
52
sub pre_store
53
{
54
my $self = shift;
55
56
my $default_section = $project->s_alias->{user_externals} if ref $project->s_alias eq 'HASH' && exists $project->s_alias->{user_externals};
57
if ( $default_section && !$self->{sections} ) {
58
$self->{sections} = $default_section;
59
}
60
61
return 1;
62
}
63
1;
utf8/plugins/users/lib/users/OA/FaceBook.pm
1
package users::OA::FaceBook;
2
3
use base "users::OA::Credential";
4
use Contenido::Globals;
5
6
sub extra_properties
7
{
8
return (
9
{ 'attr' => 'name', 'type' => 'string', 'rusname' => 'Имя в системе' },
10
{ 'attr' => 'status', 'type' => 'status', 'rusname' => 'Статус',
11
'cases' => [
12
[0, 'Не активен'],
13
[1, 'Подтвержден'],
14
[3, 'Потерян / заблокирован'],
15
],
16
},
17
)
18
}
19
20
sub class_name
21
{
22
return 'OpenAuth FaceBook';
23
}
24
25
sub class_description
26
{
27
return 'OpenAuth FaceBook';
28
}
29
30
1;
utf8/plugins/users/lib/users/OA/Google.pm
1
package users::OA::Google;
2
3
use base "users::OA::Credential";
4
use Contenido::Globals;
5
6
sub extra_properties
7
{
8
return (
9
{ 'attr' => 'name', 'type' => 'string', 'rusname' => 'Имя в системе' },
10
{ 'attr' => 'email', 'type' => 'string', 'rusname' => 'E-mail' },
11
{ 'attr' => 'status', 'type' => 'status', 'rusname' => 'Статус',
12
'cases' => [
13
[0, 'Не активен'],
14
[1, 'Подтвержден'],
15
[3, 'Потерян / заблокирован'],
16
],
17
},
18
)
19
}
20
21
sub class_name
22
{
23
return 'OpenAuth Google';
24
}
25
26
sub class_description
27
{
28
return 'OpenAuth Google';
29
}
30
31
1;
utf8/plugins/users/lib/users/OA/Mailru.pm
1
package users::OA::Mailru;
2
3
use base "users::OA::Credential";
4
use Contenido::Globals;
5
6
sub extra_properties
7
{
8
return (
9
{ 'attr' => 'name', 'type' => 'string', 'rusname' => 'Имя в системе' },
10
{ 'attr' => 'email', 'type' => 'string', 'rusname' => 'E-mail' },
11
{ 'attr' => 'status', 'type' => 'status', 'rusname' => 'Статус',
12
'cases' => [
13
[0, 'Не активен'],
14
[1, 'Подтвержден'],
15
[3, 'Потерян / заблокирован'],
16
],
17
},
18
)
19
}
20
21
sub class_name
22
{
23
return 'OpenAuth Mail.ru';
24
}
25
26
sub class_description
27
{
28
return 'OpenAuth Mail.ru';
29
}
30
31
1;
utf8/plugins/users/lib/users/OA/VK.pm
1
package users::OA::VK;
2
3
use base "users::OA::Credential";
4
use Contenido::Globals;
5
6
sub extra_properties
7
{
8
return (
9
{ 'attr' => 'name', 'type' => 'string', 'rusname' => 'Имя в системе' },
10
{ 'attr' => 'status', 'type' => 'status', 'rusname' => 'Статус',
11
'cases' => [
12
[0, 'Не активен'],
13
[1, 'Подтвержден'],
14
[3, 'Потерян / заблокирован'],
15
],
16
},
17
)
18
}
19
20
sub class_name
21
{
22
return 'OpenAuth ВКонтакте';
23
}
24
25
sub class_description
26
{
27
return 'OpenAuth ВКонтакте';
28
}
29
30
1;
utf8/plugins/users/lib/users/Phone.pm
1
package users::Phone;
2
3
use base "Contenido::Document";
4
use Contenido::Globals;
5
6
sub extra_properties
7
{
8
return (
9
{ 'attr' => 'name', 'type' => 'string', 'rusname' => 'Телефон (только номер)' },
10
{ 'attr' => 'status', 'type' => 'status', 'rusname' => 'Статус e-mail-адреса',
11
'cases' => [
12
[0, 'Не активен'],
13
[1, 'Подтвержден'],
14
[2, 'Основной'],
15
[3, 'Потерян / заблокирован'],
16
],
17
},
18
{ 'attr' => 'name_format', 'type' => 'string', 'rusname' => 'Телефон отформатированный' },
19
{ 'attr' => 'name_orig', 'type' => 'string', 'rusname' => 'Телефон (ввод пользователя)' },
20
# { 'attr' => 'login', 'type' => 'string', 'rusname' => 'Login' },
21
# { 'attr' => 'passwd', 'type' => 'string', 'rusname' => 'Password' },
22
)
23
}
24
25
sub class_name
26
{
27
return 'Телефон';
28
}
29
30
sub class_description
31
{
32
return 'Телефон';
33
}
34
35
sub search_fields
36
{
37
return ('name');
38
}
39
40
sub class_table
41
{
42
return 'users::SQL::CredentialsTable';
43
}
44
45
sub contenido_status_style
46
{
47
my $self = shift;
48
if ( $self->status == 2 ) {
49
return 'color:green;';
50
} elsif ( $self->status == 3 ) {
51
return 'color:red;';
52
}
53
}
54
55
sub pre_store
56
{
57
my $self = shift;
58
59
my $default_section = $project->s_alias->{user_phones} if ref $project->s_alias eq 'HASH' && exists $project->s_alias->{user_phones};
60
if ( $default_section && !$self->{sections} ) {
61
$self->{sections} = $default_section;
62
}
63
64
return 1;
65
}
66
1;
utf8/plugins/users/lib/users/SQL/CredentialsTable.pm
1
package users::SQL::CredentialsTable;
2
3
use strict;
4
use base 'SQL::DocumentTable';
5
6
sub db_table
7
{
8
return 'profile_credentials';
9
}
10
11
sub available_filters {
12
my @available_filters = qw(
13
_class_filter
14
_status_filter
15
_in_id_filter
16
_id_filter
17
_name_filter
18
_class_excludes_filter
19
_sfilter_filter
20
_datetime_filter
21
_date_equal_filter
22
_date_filter
23
_previous_days_filter
24
_s_filter
25
26
_excludes_filter
27
_link_filter
28
_uid_filter
29
_ext_id_filter
30
_main_filter
31
);
32
return \@available_filters;
33
}
34
35
# ----------------------------------------------------------------------------
36
# Свойства храним в массивах, потому что порядок важен!
37
# Это общие свойства - одинаковые для всех документов.
38
#
39
# attr - обязательный параметр, название атрибута;
40
# type - тип аттрибута, требуется для отображдения;
41
# rusname - русское название, опять же требуется для отображения;
42
# hidden - равен 1, когда
43
# readonly - инициализации при записи только без изменения в дальнейшем
44
# db_field - поле в таблице
45
# default - значение по умолчанию (поле всегда имеет это значение)
46
# ----------------------------------------------------------------------------
47
sub required_properties
48
{
49
my $self = shift;
50
51
my @parent_properties = grep { $_->{attr} ne 'sections' && $_->{attr} ne 'dtime' } $self->SUPER::required_properties;
52
return (
53
@parent_properties,
54
{
55
'attr' => 'uid',
56
'type' => 'pickup',
57
'rusname' => 'Идентификатор пользователя',
58
'lookup_opts' => {
59
'class' => 'mynotes::UserProfile',
60
'search_by' => 'name',
61
},
62
'db_field' => 'uid',
63
'db_type' => 'integer',
64
'db_opts' => "not null default 0",
65
},
66
{
67
'attr' => 'ext_id',
68
'type' => 'integer',
69
'rusname' => 'External ID',
70
'db_field' => 'ext_id',
71
'db_type' => 'integer',
72
'db_opts' => "not null default 0",
73
'default' => 0,
74
},
75
{
76
'attr' => 'opaque',
77
'type' => 'status',
78
'rusname' => 'Видимость',
79
'cases' => [
80
[0, 'не видно никому'],
81
[1, 'видно близким людям'],
82
[2, 'видно всем друзьям'],
83
[3, 'видно всем пользователям'],
84
[10, 'видно всем'],
85
],
86
'db_field' => 'opaque',
87
'db_type' => 'integer',
88
},
89
{
90
'attr' => 'confirm',
91
'type' => 'string',
92
'rusname' => 'Confirmation string',
93
'db_field' => 'confirm',
94
'db_type' => 'varchar(32)',
95
},
96
{
97
'attr' => 'main',
98
'type' => 'checkbox',
99
'rusname' => 'Main credential',
100
'db_field' => 'main',
101
'db_type' => 'integer',
102
},
103
{
104
'attr' => 'sections',
105
'type' => 'sections_list',
106
'rusname' => 'Секция',
107
'hidden' => 1,
108
'db_field' => 'sections',
109
'db_type' => 'integer',
110
},
111
112
);
113
}
114
115
116
sub _s_filter {
117
my ($self,%opts)=@_;
118
return undef unless ( exists $opts{s} );
119
return &SQL::Common::_generic_int_filter('d.sections', $opts{s});
120
}
121
122
sub _uid_filter {
123
my ($self,%opts)=@_;
124
return undef unless ( exists $opts{uid} );
125
return &SQL::Common::_generic_int_filter('d.uid', $opts{uid});
126
}
127
128
sub _main_filter {
129
my ($self,%opts)=@_;
130
return undef unless ( exists $opts{main} );
131
return &SQL::Common::_generic_int_filter('d.main', $opts{main});
132
}
133
134
sub _ext_id_filter {
135
my ($self,%opts)=@_;
136
return undef unless ( exists $opts{ext_id} );
137
return &SQL::Common::_generic_int_filter('d.ext_id', $opts{ext_id});
138
}
139
140
sub _name_filter {
141
my ($self,%opts)=@_;
142
return undef unless ( exists $opts{name} );
143
if ( exists $opts{ext_id} ) {
144
return &SQL::Common::_generic_text_filter('d.name', $opts{name});
145
} else {
146
my ($w1, $v1) = &SQL::Common::_generic_text_filter('d.name', $opts{name});
147
my ($w2, $v2) = &SQL::Common::_generic_int_filter('d.ext_id', 0);
148
return " ($w1) AND ($w2) ", [@$v1, @$v2];
149
}
150
}
151
152
1;
utf8/plugins/users/lib/users/SQL/UserProfile.pm
1
1
package users::SQL::UserProfile;
2
2
3
3
use base 'SQL::DocumentTable';
4
use Contenido::Globals;
4
5
5
6
sub db_table
6
7
{
…
…
152
153
'attr' => 'email',
153
154
'type' => 'string',
154
155
'rusname' => 'E-mail (primary)',
156
'hidden' => $state->{users}->use_credentials ? 1 : undef,
157
'readonly' => $state->{users}->use_credentials ? 1 : undef,
155
158
'db_field' => 'email',
156
159
'db_type' => 'text',
157
160
},
utf8/plugins/users/lib/users/State.pm.proto
20
20
$self->{db_password} = '';
21
21
$self->{db_port} = '';
22
22
$self->{profile_document_class} = '@PROFILE_DOCUMENT_CLASS@' || 'users::UserProfile';
23
$self->{use_credentials} = uc('@PROFILE_USE_CREDENTIALS@') eq 'YES' ? 1 : 0;
23
24
24
25
$self->{data_directory} = '';
25
26
$self->{images_directory} = '';
…
…
51
52
$self->{attributes}->{$_} = 'SCALAR' for qw(
52
53
db_type
53
54
profile_document_class
55
use_credentials
54
56
db_keepalive
55
57
db_host
56
58
db_port
utf8/plugins/users/lib/users/UserProfile.pm
4
4
use Digest::MD5;
5
5
use Contenido::Globals;
6
6
7
my %CREDENTIAL_FIELDS = (
8
'users::Email' => 'email',
9
'users::Phone' => 'phone',
10
'users::OA::VK' => 'vkontakte',
11
'users::OA::FaceBook' => 'facebook',
12
'users::OA::Google' => 'google',
13
'users::OA::Mailru' => 'mailru',
14
);
15
7
16
sub extra_properties
8
17
{
9
18
return (
…
…
11
20
'cases' => [
12
21
[0, 'Блокированный'],
13
22
[1, 'Активный'],
14
[2, 'Платный'],
15
[3, 'Свой/сотрудник'],
16
[4, 'VIP'],
17
23
[5, 'Временная активация'],
18
24
],
19
25
},
…
…
48
54
)
49
55
}
50
56
57
58
sub post_init {
59
my $self = shift;
60
my $opts = shift;
61
62
$self->{passwd_prev} = $self->passwd;
63
64
return if exists $opts->{ids} || exists $opts{names} || exists $opts{light};
65
if ( $self->id && $state->{users}->use_credentials ) {
66
my $creds = $keeper->get_documents(
67
uid => $self->id,
68
table => 'users::SQL::CredentialsTable',
69
return_mode => 'array_ref',
70
);
71
if ( @$creds ) {
72
my %creds;
73
foreach my $cred ( @$creds ) {
74
$cred->{keeper} = undef;
75
my $main_field = $CREDENTIAL_FIELDS{$cred->class} if exists $CREDENTIAL_FIELDS{$cred->class};
76
if ( $main_field ) {
77
my $multi_field = $main_field.'s';
78
$self->{$multi_field} = [] unless exists $self->{$multi_field};
79
push @{$self->{$multi_field}}, $cred;
80
$self->{$main_field} = $cred if $cred->main;
81
}
82
}
83
}
84
}
85
return;
86
}
87
88
51
89
sub name_full
52
90
{
53
91
my $self = shift;
…
…
112
150
}
113
151
}
114
152
153
154
sub confirm_credential {
155
my ($self, %opts) = @_;
156
my $object;
157
if ( exists $opts{confirm} && $opts{name} && $opts{class} ) {
158
($object) = $self->keeper->get_documents(
159
class => $opts{class},
160
uid => $self->id,
161
name => lc($opts{name}),
162
limit => 1,
163
);
164
if ( ref $object && $object->confirm eq $opts{confirm} ) {
165
$object->status(1);
166
$object->store;
167
}
168
} elsif ( $opts{name} && $opts{class} ) {
169
($object) = $self->keeper->get_documents(
170
class => $opts{class},
171
uid => $self->id,
172
name => lc($opts{name}),
173
limit => 1,
174
);
175
if ( ref $object ) {
176
$object->status(1);
177
$object->store;
178
}
179
}
180
return $object;
181
}
182
183
184
sub create_credential {
185
my ($self, %opts) = @_;
186
my $object;
187
if ( $opts{vkontakte} ) {
188
($object) = $self->keeper->get_documents(
189
class => users::OA::VK,
190
uid => $self->id,
191
ext_id => $opts{vkontakte},
192
limit => 1,
193
);
194
unless ( ref $object ) {
195
$object = users::OA::VK->new ($keeper);
196
$object->name( $opts{name} );
197
$object->status( 1 );
198
$object->opaque( $opts{opaque} || 0 );
199
$object->uid( $self->id );
200
$object->ava_url( $opts{avatar} );
201
$object->store;
202
}
203
} elsif ( $opts{facebook} ) {
204
($object) = $self->keeper->get_documents(
205
class => users::OA::FaceBook,
206
uid => $self->id,
207
ext_id => $opts{facebook},
208
limit => 1,
209
);
210
unless ( ref $object ) {
211
$object = users::OA::FaceBook->new ($keeper);
212
$object->name( $opts{name} );
213
$object->status( 1 );
214
$object->opaque( $opts{opaque} || 0 );
215
$object->uid( $self->id );
216
$object->ava_url( $opts{avatar} );
217
$object->store;
218
}
219
} elsif ( $opts{google} ) {
220
($object) = $self->keeper->get_documents(
221
class => users::OA::Google,
222
uid => $self->id,
223
ext_id => $opts{google},
224
limit => 1,
225
);
226
unless ( ref $object ) {
227
$object = users::OA::Google->new ($keeper);
228
$object->name( $opts{name} );
229
if ( $opts{email} ) {
230
$object->email( $opts{email} );
231
$self->create_credential( email => $opts{email}, status => 1 );
232
}
233
$object->status( 1 );
234
$object->opaque( $opts{opaque} || 0 );
235
$object->uid( $self->id );
236
$object->ava_url( $opts{avatar} );
237
$object->store;
238
}
239
} elsif ( $opts{mailru} ) {
240
($object) = $self->keeper->get_documents(
241
class => users::OA::Mailru,
242
uid => $self->id,
243
ext_id => $opts{mailru},
244
limit => 1,
245
);
246
unless ( ref $object ) {
247
$object = users::OA::Mailru->new ($keeper);
248
$object->name( $opts{name} );
249
if ( $opts{email} ) {
250
$object->email( $opts{email} );
251
$self->create_credential( email => $opts{email}, status => 1 );
252
}
253
$object->status( 1 );
254
$object->opaque( $opts{opaque} || 0 );
255
$object->uid( $self->id );
256
$object->ava_url( $opts{avatar} );
257
$object->store;
258
}
259
} elsif ( $opts{email} ) {
260
($object) = $self->keeper->get_documents(
261
class => users::Email,
262
uid => $self->id,
263
name => lc($opts{email}),
264
limit => 1,
265
);
266
unless ( ref $object ) {
267
$object = users::Email->new ($keeper);
268
$object->name( lc($opts{email}) );
269
$object->name_orig( $opts{email} );
270
$object->main( $opts{main} || 0 );
271
$object->status( $opts{status} || 0 );
272
$object->opaque( $opts{opaque} || 0 );
273
$object->uid( $self->id );
274
$object->confirm( Digest::MD5::md5_hex(int(rand(1000000)), $self->id, $opts{email}) );
275
$object->store;
276
}
277
} elsif ( $opts{phone} ) {
278
($object) = $self->keeper->get_documents(
279
class => users::Phone,
280
uid => $self->id,
281
name => $keeper->{users}->_phone_reduction( $opts{phone} ),
282
limit => 1,
283
);
284
unless ( ref $object ) {
285
$object = users::Phone->new ($keeper);
286
$object->name( $keeper->{users}->_phone_reduction($opts{phone}) );
287
$object->name_format( $keeper->{users}->_phone_format($opts{phone}) );
288
$object->name_orig( $opts{phone} );
289
$object->main( $opts{main} || 0 );
290
$object->status( $opts{status} || 0 );
291
$object->opaque( $opts{opaque} || 0 );
292
$object->uid( $self->id );
293
$object->confirm( Digest::MD5::md5_hex(int(rand(1000000)), $self->id, $opts{email}) );
294
$object->store;
295
}
296
}
297
return $object;
298
}
299
300
115
301
sub pre_store
116
302
{
117
303
my $self = shift;
…
…
119
305
my $up = $self->{keeper}->get_document_by_id ( $self->id,
120
306
class => $self->class,
121
307
);
122
if ( (ref $up && $self->passwd && $self->passwd ne $up->passwd) || (!ref $up && $self->passwd) ) {
308
my $passwd_prev = $self->{passwd_prev} || '';
309
if ( $self->passwd && $self->passwd ne $passwd_prev ) {
123
310
warn "Pass = ".$self->passwd."\n" if $DEBUG;
124
311
my $pass = Digest::MD5::md5_hex($self->passwd);
125
312
warn "Pass_hex = $pass\n" if $DEBUG;
126
313
$self->passwd($pass);
127
} elsif ( ref $up && (!$self->passwd || $self->passwd eq $up->passwd ) ) {
128
$self->passwd($up->passwd);
314
} else {
315
$self->passwd($passwd_prev);
129
316
}
130
$self->email(lc($self->email));
131
$self->login(lc($self->login));
317
$self->login( lc($self->login) );
132
318
319
if ( $state->{users}->use_credentials ) {
320
foreach my $prop ( $self->structure ) {
321
my $name = $prop->{attr};
322
if ( ref $self->$name =~ /^users::OA::/ ) {
323
my $obj = $self->$name;
324
$self->$name( $obj->ext_id );
325
} elsif ( ref $self->$name =~ /^users::/ ) {
326
my $obj = $self->$name;
327
$self->$name( $obj->name );
328
}
329
}
330
} else {
331
$self->email( $keeper->{users}->_email_reduction($self->email) );
332
}
333
133
334
my $default_section = $project->s_alias->{users} if ref $project->s_alias eq 'HASH' && exists $project->s_alias->{users};
134
335
if ( $default_section ) {
135
336
my $sections = $self->{sections};
Небольшая справка по веткам
cnddist – контейнер, в котором хранятся все дистрибутивы всех библиотек и программных пакетов, которые использовались при построении различных версий Contenido. Если какой-то библиотеки в данном хранилище нет, инсталлятор сделает попытку "подтянуть" ее с веба (например, с CPAN). Если библиотека слишком старая, есть очень большая вероятность, что ее там уже нет. Поэтому мы храним весь хлам от всех сборок. Если какой-то дистрибутив вдруг отсутствует в cnddist - напишите нам, мы положим его туда.
koi8 – отмирающая ветка, чей код, выдача и все внутренние библиотеки заточены на кодировку KOI8-R. Вносятся только те дополнения, которые касаются внешнего вида и функционала админки, баги ядра, обязательные обновления портов и мелочи, которые легко скопипастить. В дальнейшем планируется полная остановка поддержки по данной ветке.
utf8 – актуальная ветка, заточенная под UTF-8.
Внутри каждой ветки: core – исходники ядра; install – скрипт установки инсталляции; plugins – плагины; samples – "готовые к употреблению" проекты, которые можно поставить, запустить и посмотреть, как они работают.