Revision 315 (by ahitrov, 2013/04/24 19:21:22) Very strange bug thus not resolved. Store during login returns somewhere not in context
package users::UserProfile;

use base "Contenido::Document";
use Digest::MD5;
use Contenido::Globals;

my %CREDENTIAL_FIELDS = (
	'users::Email'	=> 'email',
	'users::Phone'	=> 'phone',
	'users::OA::VK'		=> 'vkontakte',
	'users::OA::FaceBook'	=> 'facebook',
	'users::OA::Google'	=> 'google',
	'users::OA::Mailru'	=> 'mailru',
);

my %CREDENTIAL_REVERSE = (
	'email'		=> 'users::Email',
	'phone'		=> 'users::Phone',
	'vkontakte'	=> 'users::OA::VK',
	'facebook'	=> 'users::OA::FaceBook',
	'google'	=> 'users::OA::Google',
	'mailru'	=> 'users::OA::Mailru',
);

sub extra_properties
{
        return (
		{ 'attr' => 'status',	'type' => 'status',     'rusname' => 'Статус пользователя',
			'cases' => [
					[0, 'Блокированный'],
					[1, 'Активный'],
					[5, 'Временная активация'],
				],
		},
		{ 'attr' => 'type',	'type' => 'status',	'rusname' => 'Тип аккаунта',
			'cases' => [
					[0, 'Обычный пользователь'],
					[1, 'Продвинутый пользователь'],
					[2, 'Модератор'],
					[10, 'Администратор'],
				],
		},
		{ 'attr' => 'visibility',   'type' => 'status',     'rusname' => 'Область видимости',
			'cases' => [
					[0, 'Данные моего аккаунта видны только мне'],
					[1, 'Данные моего аккаунта видны всем'],
					[2, 'Данные моего аккаунта видны друзьям'],
					[3, 'Данные моего аккаунта видны друзьям и членам клубов'],
				],
		},
		{ 'attr' => 'country',	'type' => 'string',	'rusname' => 'Страна' },
		{ 'attr' => 'passwd',	'type' => 'password',	'rusname' => 'Пароль', 'rem' => '(<font color="red">Не отображается. Указывать при создании и для изменения</font>)' },
		{ 'attr' => 'confirm',	'type' => 'string',	'rusname' => 'Код подтверждения', hidden => 1 },
		{ 'attr' => 'secmail',	'type' => 'string',	'rusname' => 'E-mail (secondary)' },
		{ 'attr' => 'q1',	'type' => 'string',	'rusname' => 'Контрольный вопрос 1' },
		{ 'attr' => 'a1',	'type' => 'string',	'rusname' => 'Контрольный ответ 1' },
		{ 'attr' => 'q2',	'type' => 'string',	'rusname' => 'Контрольный вопрос 2' },
		{ 'attr' => 'a2',	'type' => 'string',	'rusname' => 'Контрольный ответ 2' },
		{ 'attr' => 'account',	'type' => 'string',	'rusname' => 'Сумма на счете' },
		{ 'attr' => 'interests',	'type' => 'text',	'rusname' => 'Жизненные интересы', rows => 10 },
		{ 'attr' => 'origin',		'type' => 'text',	'rusname' => 'Ориджин',	rows => 4 },
		{ 'attr' => 'avatar',		'type' => 'image',	'rusname' => 'Аватар', crop => ['32x32','150x150'], preview => ['200x200'] },
        )
}


sub post_init {
    my $self = shift;
    my $opts = shift;

    $self->{passwd_prev} = $self->passwd;

    return	if exists $opts->{ids} || exists $opts{names} || exists $opts{light};
    if ( $self->id && $state->{users}->use_credentials ) {
	$self->{credentials_available} = {};
	my $creds = $keeper->get_documents(
			uid	=> $self->id,
			table	=> 'users::SQL::CredentialsTable',
			return_mode	=> 'array_ref',
		);
	if ( @$creds ) {
		my %creds;
		foreach my $cred ( @$creds ) {
			$cred->{keeper} = undef;
			my $main_field = $CREDENTIAL_FIELDS{$cred->class}	if exists $CREDENTIAL_FIELDS{$cred->class};
			$self->{credentials_available}{$main_field} = 1;
			if ( $main_field ) {
				my $multi_field = $main_field.'s';
				$self->{$multi_field} = []	unless exists $self->{$multi_field};
				push @{$self->{$multi_field}}, $cred;
				$self->{$main_field} = $cred	if $cred->main;
			}
		}
	}
    }
    return;
}


sub name_full
{
    my $self = shift;
    my $name = $self->name;
    if ( $name =~ /^(.*?),[\ \t]+(.*)$/ ) {
	$name = $2.' '.$1;
    }
    return $name;
}

sub name_part
{
    my $self = shift;
    my $name = $self->name;
    if ( $name =~ /^(.*?),[\ \t]+(.*)$/ ) {
	$name = $2;
    }
    return $name;
}

sub name_family
{
    my $self = shift;
    my $name = $self->name;
    if ( $name =~ /^(.*?),[\ \t]+(.*)$/ ) {
	$name = $1;
    }
    return $name;
}

sub class_name
{
	return 'Профиль пользователя';
}

sub class_description
{
	return 'Профиль пользователя';
}

sub search_fields
{
	return ('email', 'name', 'login');
}

sub class_table
{
	return 'users::SQL::UserProfile';
}

sub contenido_status_style
{
	my $self = shift;
	if ( $self->status == 2 ) {
		return 'color:green;';
	} elsif ( $self->status == 3 ) {
		return 'color:olive;';
	} elsif ( $self->status == 4 ) {
		return 'color:green;';
	} elsif ( $self->status == 5 ) {
		return 'color:red;';
	}
}


sub get_credentials {
    my ($self, $name, %opts) = @_;
    my $objects;
    if ( $name ) {
	return undef	unless exists $CREDENTIAL_REVERSE{$name};
	my $names = $name.'s';
	if ( exists $self->{credentials_available}{$name} ) {
		$objects = $self->{$names};
	}
    } elsif ( my @keys = keys %{$self->{credentials_available}} ) {
	$objects = {};
	foreach my $key ( @keys ) {
		my $names = $key.'s';
		push @{$objects->{$key}}, $self->{$names};
	}
    }
    return $objects;
}

sub confirm_credential {
    my ($self, %opts) = @_;
    my $object;
    if ( exists $opts{confirm} && $opts{name} && $opts{class} ) {
	($object) = $self->keeper->get_documents(
			class	=> $opts{class},
			uid	=> $self->id,
			name	=> lc($opts{name}),
			limit	=> 1,
		);
	if ( ref $object && $object->confirm eq $opts{confirm} ) {
		$object->status(1);
		$object->store;
	}
    } elsif ( $opts{name} && $opts{class} ) {
	($object) = $self->keeper->get_documents(
			class	=> $opts{class},
			uid	=> $self->id,
			name	=> lc($opts{name}),
			limit	=> 1,
		);
	if ( ref $object ) {
		$object->status(1);
		$object->store;
	}
    }
    return $object;
}


sub create_credential {
    my ($self, %opts) = @_;
    my $object;
    if ( $opts{vkontakte} ) {
	($object) = $self->keeper->get_documents(
			class	=> 'users::OA::VK',
			ext_id	=> $opts{vkontakte},
			limit	=> 1,
		);
	return undef	if ref $object && $object->uid != $self->id;
        unless ( ref $object ) {
		$object = users::OA::VK->new ($keeper);
		$object->name( $opts{name} );
		$object->ext_id( $opts{vkontakte} );
		$object->status( 1 );
		$object->opaque( $opts{opaque} || 0 );
		$object->uid( $self->id );
		$object->ava_url( $opts{avatar} );
		$object->store;
	}
    } elsif ( $opts{facebook} ) {
	($object) = $self->keeper->get_documents(
			class	=> 'users::OA::FaceBook',
			ext_id	=> $opts{facebook},
			limit	=> 1,
		);
	return undef	if ref $object && $object->uid != $self->id;
        unless ( ref $object ) {
		$object = users::OA::FaceBook->new ($keeper);
		$object->name( $opts{name} );
		$object->ext_id( $opts{facebook} );
		$object->status( 1 );
		$object->opaque( $opts{opaque} || 0 );
		$object->uid( $self->id );
		$object->ava_url( $opts{avatar} );
		$object->store;
	}
    } elsif ( $opts{google} ) {
	($object) = $self->keeper->get_documents(
			class	=> 'users::OA::Google',
			ext_id	=> $opts{google},
			limit	=> 1,
		);
	return undef	if ref $object && $object->uid != $self->id;
        unless ( ref $object ) {
		$object = users::OA::Google->new ($keeper);
		$object->name( $opts{name} );
		$object->ext_id( $opts{google} );
		if ( $opts{email} ) {
			$object->email( $opts{email} );
			$self->create_credential( email => $opts{email}, status => 1 );
		}
		$object->status( 1 );
		$object->opaque( $opts{opaque} || 0 );
		$object->uid( $self->id );
		$object->ava_url( $opts{avatar} );
		$object->store;
	}
    } elsif ( $opts{mailru} ) {
	($object) = $self->keeper->get_documents(
			class	=> 'users::OA::Mailru',
			ext_id	=> $opts{mailru},
			limit	=> 1,
		);
	return undef	if ref $object && $object->uid != $self->id;
        unless ( ref $object ) {
		$object = users::OA::Mailru->new ($keeper);
		$object->name( $opts{name} );
		$object->ext_id( $opts{mailru} );
		if ( $opts{email} ) {
			$object->email( $opts{email} );
			$self->create_credential( email => $opts{email}, status => 1 );
		}
		$object->status( 1 );
		$object->opaque( $opts{opaque} || 0 );
		$object->uid( $self->id );
		$object->ava_url( $opts{avatar} );
		$object->store;
	}
    } elsif ( $opts{email} ) {
	($object) = $self->keeper->get_documents(
			class   => 'users::Email',
			name    => lc($opts{email}),
			limit   => 1,
		);
	return undef	if ref $object && $object->uid != $self->id;
	unless ( ref $object ) {
		$object = users::Email->new ($keeper);
		$object->name( lc($opts{email}) );
		$object->name_orig( $opts{email} );
		$object->main( $opts{main} || 0 );
		$object->status( $opts{status} || 0 );
		$object->opaque( $opts{opaque} || 0 );
		$object->uid( $self->id );
		$object->confirm( Digest::MD5::md5_hex(int(rand(1000000)), $self->id, $opts{email}) );
		$object->store;
	}
    } elsif ( $opts{phone} ) {
	($object) = $self->keeper->get_documents(
			class   => 'users::Phone',
			name    => $keeper->{users}->_phone_reduction( $opts{phone} ),
			limit   => 1,
		);
	return undef	if ref $object && $object->uid != $self->id;
	unless ( ref $object ) {
		$object = users::Phone->new ($keeper);
		$object->name( $keeper->{users}->_phone_reduction($opts{phone}) );
		$object->name_format( $keeper->{users}->_phone_format($opts{phone}) );
		$object->name_orig( $opts{phone} );
		$object->main( $opts{main} || 0 );
		$object->status( $opts{status} || 0 );
		$object->opaque( $opts{opaque} || 0 );
		$object->uid( $self->id );
		$object->confirm( Digest::MD5::md5_hex(int(rand(1000000)), $self->id, $opts{email}) );
		$object->store;
	}
    }
    return $object;
}


sub pre_store
{
	my $self = shift;

	my $passwd_prev = $self->{passwd_prev} || '';
	if ( $self->passwd && $self->passwd ne $passwd_prev  ) {
		warn "Pass = ".$self->passwd."\n"			if $DEBUG;
		my $pass = Digest::MD5::md5_hex($self->passwd);
		warn "Pass_hex = $pass\n"				if $DEBUG;
		$self->passwd($pass);
	} else {
		$self->passwd($passwd_prev);
	}
	$self->login( lc($self->login) );

	if ( $state->{users}->use_credentials ) {
		foreach my $prop ( $self->structure ) {
			my $name = $prop->{attr};
			if ( ref $self->{$name} =~ /^users::OA::/ ) {
				my $obj = $self->{$name};
				$self->$name( $obj->ext_id );
			} elsif ( ref $self->{$name} =~ /^users::/ ) {
				my $obj = $self->{$name};
				$self->$name( $obj->name );
			}
		}
	} else {
		$self->email( $keeper->{users}->_email_reduction($self->email) );
	}

	my $default_section = $project->s_alias->{users}	if ref $project->s_alias eq 'HASH' && exists $project->s_alias->{users};
	if ( $default_section ) {
		my $sections = $self->{sections};
		if ( ref $sections eq 'ARRAY' && scalar @$sections ) {
			my @new_sects = grep { $_ != $default_section } @$sections;
			push @new_sects, $default_section;
			$self->sections(@new_sects);
		} elsif ( $sections && !ref $sections && $sections != $default_section ) {
			my @new_sects = ($default_section, $sections);
			$self->sections(@new_sects);
		} else {
			$self->sections($default_section);
		}
	}
	return 1;
}


sub post_delete
{
    my $self = shift;

    if ( $state->{users}->use_credentials ) {
	my $creds = $keeper->get_documents(
			table	=> 'users::SQL::CredentialsTable',
			uid	=> $self->id,
			return_mode	=> 'array_ref',
		);
	map { $_->delete( attachments => 1 ) } @$creds;
    }
    1;
}

1;