Revision 196

Date:
2012/03/15 18:28:32
Author:
ahitrov
Revision Log:
Users plugin
Files:

Legend:

 
Added
 
Removed
 
Modified
  • utf8/plugins/users/comps/contenido/users/autohandler

     
    1 <%init>
    2
    3 $r->content_type('text/html');
    4 $m->call_next();
    5
    6 </%init>
  • utf8/plugins/users/comps/contenido/users/components/__section_tree__.msn

     
    1 %# vim:syn=mason:
    2 % users_index_tree( $sect, 0, \$line, $level, $mode, $profile, $width_limit, $root );
    3 <%once>
    4
    5 use Encode;
    6
    7 </%once>
    8 <%args>
    9
    10 $root => 1
    11 $level => 3
    12 $mode => 1
    13 $width_limit => undef
    14
    15 </%args>
    16 <%init>
    17 my $profile = $m->comp('/contenido/components/context.msn', name => 'profile');
    18
    19 sub users_index_tree
    20 {
    21 my ($sect, $offset, $line_ref, $count_offset, $viewmode, $profile, $width_limit, $root) = @_;
    22 my $section_access = $user->section_accesses($user, $sect->{id});
    23
    24 my $spacer = '';
    25 for(my $c=1; $c<$offset; $c++)
    26 {
    27 $spacer = $spacer.(($c == $offset-1) ? '&nbsp;&nbsp;&raquo;&nbsp;&nbsp;' : '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;');
    28 }
    29 if( $sect->{id} && ($sect->{id} != 1) && ($offset != 0) && $section_access > 0)
    30 {
    31 $$line_ref++;
    32
    33 my $href = 'sections.html?id='.$sect->id;
    34
    35 my $sname = decode("utf-8", $sect->name());
    36 if ( defined $width_limit && $offset + length($sname) > $width_limit ) {
    37 $sname = substr($sname, 0, $width_limit - $offset);
    38 $sname .= '&nbsp;...';
    39 }
    40 $sname = encode("utf-8", $sname);
    41 my $statstyle = $sect->contenido_status_style ? ' style="' . $sect->contenido_status_style . '"' : '';
    42 my @properties = $sect->structure();
    43 my ($statprop) = grep { $_->{attr} eq 'status' } @properties;
    44 my ($statcase) = grep { $_->[0] == $sect->status } @{$statprop->{cases}} if exists $statprop->{cases} && ref $statprop->{cases} eq 'ARRAY';
    45 my $statname = $statcase->[1] if ref $statcase;
    46 my $html_sect = '<span'.($statstyle).(!$sect->status ? ' class="hiddensect"' : '').'>'.($section_access ? '<a href="'.$href.'"'.$statstyle.'>' : '').$sname.($section_access ? '</a>' : '') . '&nbsp;'.($sect->status != 1 && $statname ? '&nbsp;<span style="font-size:11px;">('.$statname.')</span>' : '').'</span>';
    47 my $style = ($offset == 1) ? ($viewmode ? ' style="font-size:110%;"':' style="font-size:95%;"') : '';
    48
    49 $m->out(<<EOT);
    50 <tr>
    51 <td align="right">&nbsp;${$line_ref}&nbsp;<a href="section.html?id=$sect->{id}&move=up&ret=$root"><img src="/contenido/i/ico-up-9x10.gif" border=0 alt="Переместить секцию на шаг вверх"></a>&nbsp;<a href="section.html?id=$sect->{id}&move=down&ret=$root"><img src="/contenido/i/ico-down-9x10.gif" border=0 alt="Переместить секцию на шаг вниз"></a></td>
    52 <td><table cellpadding="0" cellspacing="0" border="0">
    53 <tr valign="top">
    54 <td width="10">&nbsp;</td>
    55 <td>$spacer</td>
    56 <td nowrap $style>$html_sect</td>
    57 </tr>
    58 </table>
    59 </td>
    60 EOT
    61
    62 if ($viewmode)
    63 {
    64 my $fhref = '/contenido/?set_context=filter-'.$sect->id();
    65 $m->out(qq^\n<td align="center" nowrap><a href="$fhref">уст.фильтр</a>^);
    66 $m->out(qq^&nbsp;&nbsp;&nbsp;<a href="document.html?sect_id=$sect->{id}">доб.докум</a>^) if $section_access == 2;
    67 $m->out("</td>");
    68 }
    69
    70 $m->out('</tr>');
    71 }
    72
    73 my $childs = $sect->{childs} || [];
    74 if( ref($childs) && @$childs && $offset < $count_offset )
    75 {
    76 $offset++;
    77 foreach my $child (@$childs)
    78 {
    79 next if ( $child->class() ne 'users::Section' );
    80 next if (! $request->{cCLASSES}->{$child->class()});
    81 users_index_tree( $child, $offset, $line_ref, $count_offset, $viewmode, $profile, $width_limit, $root );
    82 }
    83 $offset--;
    84 }
    85 }
    86
    87 my $sect = $keeper->get_tree(light=>1, root=>$root);
    88 return undef unless ref $sect;
    89
    90 $user->get_accesses();
    91
    92 my $line = 0;
    93 $request->{cCLASSES} = {};
    94 $request->{cCLASSES}->{'users::Section'} = 1;
    95 if (ref($request->{tab}->{sections}))
    96 {
    97 map { $request->{cCLASSES}->{$_} = 1 } (@{ $request->{tab}->{sections} });
    98 }
    99 return undef if (scalar(keys(%{ $request->{cCLASSES} })) == 0);
    100
    101 </%init>
  • utf8/plugins/users/comps/contenido/users/components/find_user.msn

     
    1 <script type="text/javascript">
    2 <!--
    3 function StartSearch () {
    4 var oForm = document.forms['user_search'];
    5 var oFormStart = document.forms['start_search'];
    6 % my $i = 0;
    7 % foreach my $field ( @fields ) {
    8 <% $i++ ? '} else if' : 'if' %> ( oForm.<% $field %>.value ) {
    9 oFormStart.search.value = oForm.<% $field %>.value;
    10 oFormStart.search_by.value = oForm.<% $field %>.name;
    11 % }
    12 % if ($i) {
    13 }
    14 % }
    15 if ( oFormStart.search.value && oFormStart.search_by.value ) {
    16 oFormStart.submit();
    17 }
    18 }
    19 //-->
    20 </script>
    21 <fieldset>
    22 <legend>Поиск пользователя</legend>
    23 <form id="start_search" name="start_search" action="<% $url %>" method="get">
    24 <input type="hidden" name="search" value="">
    25 <input type="hidden" name="search_by" value="">
    26 </form>
    27 <form id="user_search" name="user_search" action="<% $url %>" method="get">
    28 <table cellspacing="2" cellpadding="0" border="0" class="tform">
    29 <tr><td height="3"></td></tr>
    30 % foreach my $field ( @fields ) {
    31 <tr><td align="right"><b><% $props{$field} %>:&nbsp;</b></td>
    32 <td><input type="text" name="<% $field %>" size="40" value="<% $search_by && $search_by eq $field ? $search : '' %>"></td></tr>
    33 % }
    34
    35 <tr><td align="right">&nbsp;</td>
    36 <td align="right"><input type="button" size="40" value="Искать" onclick="StartSearch();">
    37 &nbsp;&nbsp;&nbsp;<a href="<% $url %>">сбросить фильтр</a>
    38 </td></tr>
    39 <tr><td height="5"></td></tr>
    40 </table>
    41 </form>
    42 </fieldset>
    43 <%args>
    44
    45 $url => 'index.html'
    46 $search => undef
    47 $search_by => undef
    48
    49 </%args>
    50 <%init>
    51
    52 my @fields;
    53 my @properties;
    54 my %props;
    55 my $class = $state->{users}->profile_document_class;
    56 my $object = $class->new ($keeper);
    57 if ( ref $object ) {
    58 @fields = $object->search_fields;
    59 @fields = qw( login email nickname name ) unless @fields;
    60 @properties = $object->structure();
    61 %props = map { $_->{attr} => $_->{rusname} } @properties;
    62 } else {
    63 @fields = qw( login email nickname name );
    64 %props = (
    65 'login' => { 'Логин' },
    66 'email' => { 'E-mail' },
    67 'nickname' => { 'Ник' },
    68 'name' => { 'Ф.И.О.' },
    69 );
    70 }
    71
    72 </%init>
  • utf8/plugins/users/comps/contenido/users/components/subsection.msn

     
    1 <fieldset>
    2 <legend>Подразделы</legend>
    3
    4 <table width="100%" border="0" cellpadding="3" cellspacing="0" class="tlistdocs">
    5 <tr bgcolor="#efefef">
    6 <th align="center" width="1%">N</th>
    7 <th>Название</th>
    8
    9 <& "/contenido/users/components/__section_tree__.msn", root=>$section->id, level=>3, mode=>0, width_limit => 30 &>
    10
    11 </table>
    12 % if ($section_access == 2)
    13 % {
    14 <div style="font-size:70%;font-family:Tahoma;margin:5px 4px 10px 4px;"><b><a href="section.html?sect_id=<% $section->id %>">Создать подраздел &raquo;</a></b></div>
    15 % }
    16 <div style="font-size:70%;font-family:Tahoma;margin:5px 4px 10px 4px;"><b><a href="./?set_context=filter-<% $section->id %>">Установить в качестве фильтра &raquo;</a></b></div>
    17 </fieldset>
    18
    19
    20 <%ARGS>
    21
    22 $section => undef
    23
    24 </%ARGS>
    25 <%INIT>
    26 return undef if (! ref($section));
    27 my $section_access = $user->section_accesses($user, $section->id);
    28 </%INIT>
  • utf8/plugins/users/comps/contenido/users/components/tasks.msn

     
    1 <%init>
    2
    3 return (
    4 {
    5 'attr' => 'structure',
    6 'rusname' => 'Редактирование параметров сайта',
    7 'component' => 'structure.msn',
    8 },
    9 {
    10 'attr' => 'project',
    11 'rusname' => 'Редактирование параметров объектов',
    12 'component' => 'project.msn',
    13 },
    14 {
    15 'attr' => 'finder',
    16 'rusname' => 'Отбор документов',
    17 'component' => 'finder.msn',
    18 },
    19 {
    20 'attr' => 'users',
    21 'rusname' => 'Список пользователей системы',
    22 'component' => 'users.msn',
    23 },
    24 {
    25 'attr' => 'cache',
    26 'rusname' => 'Очистить кэш сайта',
    27 'component' => 'cache.msn',
    28 },
    29 );
    30
    31 </%init>
  • utf8/plugins/users/comps/contenido/users/dhandler

     
    1 %#<pre><% Dumper ($m->dhandler_arg) %></pre>
    2 <& $call, %ARGS &>
    3 <%init>
    4
    5 my $call;
    6 if ( $m->dhandler_arg =~ /section.html/ ) {
    7 $call = '/contenido/section.html';
    8 } elsif ( $m->dhandler_arg =~ /sections.html/ ) {
    9 $call = 'index.html';
    10 } elsif ( $m->dhandler_arg =~ /document.html/ ) {
    11 $call = '/contenido/document.html';
    12 } elsif ( $m->dhandler_arg =~ /confirm.html/ ) {
    13 $call = '/contenido/confirm.html';
    14 } elsif ( $m->dhandler_arg =~ /document_links.html/ ) {
    15 $call = '/contenido/document_links.html';
    16 } elsif ( $r->uri eq '/contenido/users/' ) {
    17 $call = '/contenido/users/index.html';
    18 } else {
    19 &abort404;
    20 }
    21
    22 </%init>
  • utf8/plugins/users/comps/contenido/users/document.html

     
    1 %# vim:syn=mason
    2 <& "/contenido/components/header.msn" &>
    3 <& "/contenido/components/naviline.msn", sect_id => $owner->id &>
    4
    5 % if ($error) {
    6 <div align="center" style="font-size:110%; color:red;">
    7 <% $error %>
    8 </div>
    9 <br><br>
    10 % }
    11
    12 % if (!ref($document)) {
    13 % if ($id) {
    14 <div align="center" style="font-size:110%; color:red;">
    15 Документ с идентификатором <% $id %> не найден
    16 </div>
    17 <br><br>
    18 % } elsif ($class) {
    19 <!-- Блок с выбором нового документа для создания -->
    20 <table width="50%" border="0"><tr><td>
    21 <fieldset>
    22 <legend>Выберите тип документа для создания</legend>
    23 <& "/contenido/components/new_objects_form.msn", proto => 'documents', sect_id => $owner->id &>
    24 </fieldset>
    25 </td></tr></table>
    26 % } else {
    27 <div align="center" style="font-size:110%; color:red;">
    28 Неверный вызов документа!!! (отсутствуют id и class одновременно)
    29 </div>
    30 <br><br>
    31 % }
    32
    33 % } else {
    34
    35 <& "/contenido/components/obj_list_js.msn", object => $document &>
    36 <& "/contenido/components/object_form.msn",
    37 object => $document,
    38 proto => 'documents',
    39 sect_id => $owner->id,
    40 clone => $clone,
    41 filter_params => \%filter_params,
    42 &>
    43 % if (ref($document) && ($document->id))
    44 % {
    45
    46 <!-- Связи и привязки к рубрикам -->
    47
    48 <br>
    49
    50 <table width="100%" cellspacing="5" cellpadding="0" border="0">
    51 <tr>
    52 <td width=50% valign=top>\
    53 <& "/contenido/components/document_sections.msn", document => $document &>\
    54 <& "/contenido/components/user_sections.msn", luser => $document &>\
    55 % if ( $m->comp_exists ("/contenido/components/pbase_rubrics.msn") ) {
    56 <& "/contenido/components/pbase_rubrics.msn", document => $document &>\
    57 % }
    58 </td>
    59 <td width=50% valign=top>\
    60 % if ( $m->comp_exists ("/contenido/components/pbase_links.msn") ) {
    61 <& "/contenido/components/pbase_links.msn", document => $document &>\
    62 % }
    63 <iframe id="links" src="/contenido/document_links.html?id=<% $document->id() %>&class=<% $document->class() %>" width="100%" height="700" frameborder="0"></iframe>
    64
    65 </td>
    66 </tr>
    67 </table>
    68
    69 <!-- / Связи и привязки к рубрикам -->
    70
    71 % }
    72 % }
    73
    74 </body>
    75 </html>
    76 <%ARGS>
    77 $p => 1
    78 $class => undef
    79 $sect_id => undef
    80 $s_alias => undef
    81 $id => undef
    82 $delete => undef
    83 $save => undef
    84 $clone => undef
    85 $activate => undef
    86 $deactivate => undef
    87 </%ARGS>
    88 <%INIT>
    89
    90 &abort404 unless $class;
    91 my $error='';
    92 ### !!! При добавлении переменных в ARGS их надо внести в список исключений в структуре ниже
    93
    94 my $filter = $m->comp('/contenido/components/context.msn', name => 'filter');
    95
    96 my $document;
    97 my $new;
    98
    99 if ($id && ($id !~ /\D/) && ($id > 0)) {
    100 $document = $keeper->get_document_by_id($id, class=>$class);
    101 if ( $clone && exists $document->{'attributes'}->{'dtime'} ) {
    102 $document->dtime(undef);
    103 }
    104 } elsif ( ($class) && (length($class)>0) && (! ref($document)) ) {
    105 $document = new $class ($keeper);
    106 $new = 1;
    107 my @properties = $document->structure();
    108 foreach my $prop ( @properties ) {
    109 my $attr = $prop->{attr};
    110 ### !!! Если не стандартная переменная, то можем инициализировать
    111 if ( exists $ARGS{$attr} && ! grep { $prop->{attr} eq $_ } qw( class sect_id id delete save clone s_alias activate deactivate ) ) {
    112 $document->$attr($ARGS{$attr});
    113 }
    114 }
    115 }
    116 &abort404 unless ref $document;
    117
    118 my @props = $document->structure();
    119 my %filter_params;
    120 if ($ARGS{use_section} && !grep { $_->{attr} eq 'use_section' } @props ) {
    121 $filter_params{use_section} = $ARGS{use_section};
    122 $filter_params{class} = $document->class;
    123 }
    124 $filter_params{alpha} = $ARGS{alpha} if $ARGS{alpha} && !grep { $_->{attr} eq 'alpha' } @props;
    125 $filter_params{alpha_search} = $ARGS{alpha_search} if $ARGS{alpha_search} && !grep { $_->{attr} eq 'alpha_search' } @props;
    126 $filter_params{search_by} = $ARGS{search_by} if $ARGS{search_by} && !grep { $_->{attr} eq 'search_by' } @props;
    127 $filter_params{search} = $ARGS{search} if $ARGS{search} && !grep { $_->{attr} eq 'search' } @props;
    128 $filter_params{s} = $ARGS{s} if $ARGS{s} && !grep { $_->{attr} eq 's' } @props;
    129 $filter_params{p} = $p if $p > 1;
    130 my $return_params = join ('&', map { $_.'='.$filter_params{$_} } grep { $_ ne 's' } keys %filter_params );
    131
    132
    133 if ($s_alias) {
    134 $sect_id = $project->s_alias->{$s_alias};
    135 }
    136
    137 if ( (! $sect_id) && (ref($document)) && ($document->id) ) {
    138 $sect_id = $document->section();
    139 }
    140 my $owner = $keeper->get_section_by_id ($sect_id || $Contenido::Section::ROOT || 1);
    141
    142 if (! ref($owner)) {
    143 $owner = $keeper->get_section_by_id ($Contenido::Section::ROOT || 1);
    144 }
    145 if (! ref($owner)) {
    146 warn "Contenido Die: Не могу найти корневую секцию\n";
    147 return undef;
    148 }
    149
    150 if (ref($document) && $document->id() && $document->section()) {
    151 my $document_access = $user->section_accesses($user, $document->section);
    152 if ($document_access != 2) {
    153 $m->clear_buffer;
    154 $m->abort(403);
    155 }
    156 }
    157
    158 # Удаление...
    159 if (defined($id) && ($id > 0) && ($delete == 1)) {
    160 $document->delete( attachments => 1 );
    161
    162 $m->redirect("sections.html?id=".($filter_params{s} || $owner->id).($return_params ? '&'.$return_params : ''));
    163 }
    164
    165 # Активация...
    166 if (defined($id) && ($id > 0) && ($activate == 1)) {
    167 $document->status(1);
    168 $document->store;
    169
    170 $m->redirect("sections.html?id=".($filter_params{s} || $owner->id).($return_params ? '&'.$return_params : ''));
    171 }
    172
    173 # Дективация...
    174 if (defined($id) && ($id > 0) && ($deactivate == 1)) {
    175 $document->status(0);
    176 $document->store;
    177
    178 $m->redirect("sections.html?id=".($filter_params{s} || $owner->id).($return_params ? '&'.$return_params : ''));
    179 }
    180
    181 # Сохранение существующего документа или создание нового...
    182 # Кстати, пока никак не обрабатываются связи...
    183 elsif ( $save == 1 )
    184 {
    185 my $clonesource;
    186 if ( $clone ) {
    187 $clonesource = $keeper->get_document_by_id ($clone,
    188 class => $document->class,
    189 );
    190 }
    191 if ($m->comp('/contenido/components/set_properties.msn', object => $document, SETS => \%ARGS) != 1)
    192 {
    193 # Ошибка, надо бы обработать...
    194 warn "Contenido Warning: Не могу установить значения полей!\n";
    195 }
    196 if ( $clone ) {
    197 $m->comp('/contenido/components/clone_attachments.msn', object => $document, source => $clonesource );
    198 $document->sections( $clonesource->sections );
    199 } elsif ( $new ) {
    200 $document->sections( $owner->id, $filter > 0 ? ($filter) : ());
    201 }
    202
    203
    204 unless ($document->store()) {
    205 # Ошибка, надо бы обработать...
    206 $error="Ошибка сохранения ($keeper->{last_error})";
    207 } else {
    208
    209 if ($ARGS{_save_and_leave}) {
    210 $m->redirect("sections.html?id=".($filter_params{s} || $owner->id).($return_params ? '&'.$return_params : ''));
    211 } elsif ($ARGS{_save_and_again}) {
    212 $m->redirect("document.html?class=".$document->class()."&sect_id=".($filter_params{s} || $owner->id).($return_params ? '&'.$return_params : ''));
    213 }
    214
    215
    216 $m->redirect("document.html?id=".$document->id()."&class=".$document->class().(exists $filter_params{s} ? '&s='.$filter_params{s} : '').($return_params ? '&'.$return_params : ''));
    217 }
    218 }
    219
    220 </%INIT>
  • utf8/plugins/users/comps/contenido/users/document_filter_list.html

     
    1 <& "/contenido/components/title.msn" &>
    2 <div style="font:bold 13px Verdana; margin:4px;">Класс: <span style="color:teal;"><% $class %></span>
    3 <span style="font:11px Verdana;">(<a href="document.html?class=<% $class %>&<% $field %>=<% $id %>" target="_blank">создать новый</a>)</span></div>
    4 % if ( ref $docs eq 'ARRAY' && @$docs ) {
    5 % if ($total > $size) {
    6 <div style="font-size:75%; font-family:Arial; text-align:center;">
    7 <& /inc/pages_.msn, p => $p, n => $size, total => $total, params => {%ARGS} &></div>
    8 % }
    9 % my @props = sort { $a->{column} <=> $b->{column} } grep { exists $_->{column} } $docs->[0]->required_properties;
    10 <table width="100%" border="0" cellpadding="4" cellspacing="0" class="tlistdocs">
    11 <tr bgcolor="#efefef">
    12 % foreach my $prop (@props) {
    13 <th><% $prop->{rusname} %></th>
    14 % }
    15 </tr>
    16 % foreach my $doc (@$docs) {
    17 % my $color = $doc->contenido_status_style ? $doc->contenido_status_style :
    18 % $doc->status == 1 ? 'blue' :
    19 % $doc->status == 0 ? 'gray' : 'blue';
    20
    21 %# my ($stat) = grep { $_->{attr} eq 'status' } @props;
    22 %# my ($case) = grep { $_->[0] == $banner->status } @{ $stat->{cases} } if ref $stat eq 'HASH' && exists $stat->{cases};
    23 <tr>
    24 % foreach my $prop (@props) {
    25 % my $attr = $prop->{attr};
    26 % if ( $attr =~ /dtime/ ) {
    27 <td><a href="document.html?id=<% $doc->id %>&class=<% $doc->class %>"
    28 style="<% $color %>" target="_blank"><& "/contenido/components/show_dtime.msn", dtime => $doc->$attr &></a></td>
    29 % } elsif ( $prop->{type} eq 'status' ) {
    30 % my ($case) = grep { $_->[0] == $doc->$attr } @{$prop->{cases}};
    31 <td><% ref $case ? $case->[1] : 'Статус: '.$prop->$attr %></td>
    32 % } else {
    33 <td><a href="document.html?id=<% $doc->id %>&class=<% $doc->class %>"
    34 style="<% $color %>" target="_blank"><% $doc->$attr %></a></td>
    35 % }
    36 % }
    37 </tr>
    38 % }
    39 </table>
    40 % }
    41 %#<pre><% Dumper($docs->[0]->required_properties) %></pre>
    42 <%args>
    43 $id => undef
    44 $filter => undef
    45 $field => undef
    46 $class => undef
    47 $order_by => undef
    48 $p => 1
    49 </%args>
    50 <%init>
    51
    52 my ($docs, $total);
    53 my $size = 15;
    54 if ( $id && $filter && $class ) {
    55 my %opts = ();
    56 $opts{$filter} = $id;
    57 $opts{order_by} = $order_by if $order_by;
    58 $docs = $keeper->get_documents (
    59 class => $class,
    60 return_mode => 'array_ref',
    61 offset => ($p-1)*$size,
    62 limit => $size,
    63 %opts,
    64 );
    65 $total = $keeper->get_documents (
    66 class => $class,
    67 count => 1,
    68 %opts,
    69 );
    70 } else {
    71 return;
    72 }
    73
    74 </%init>
  • utf8/plugins/users/comps/contenido/users/index.html

     
    1 <& "/contenido/components/header.msn" &>
    2 <& "/contenido/components/naviline.msn", sect_id => $owner->id &>
    3
    4 <table width="100%" cellspacing="0" cellpadding="0" border="0">
    5 <tr valign="top">
    6 <td width="35%">
    7
    8 <& /contenido/users/components/find_user.msn,
    9 search => $search, search_by => $search_by,
    10 url=>'sections.html' &>
    11
    12 <& "/contenido/users/components/subsection.msn", section => $owner &>
    13 <& "/contenido/components/class_filter.msn", class=> $class, section => $owner &>
    14
    15 % if (( $owner->id ) && ($owner->id > 0) && $owner->id != 1 )
    16 % {
    17 <& "/contenido/components/section_info.msn", section => $owner &>
    18 % }
    19
    20 </td>
    21 <td width="2%">&nbsp;</td>
    22 <td width="65%">
    23
    24 % if($owner->id) {
    25
    26 <fieldset>
    27 <legend>Документы\
    28 % if ($class) {
    29 класса <% $class %>\
    30 % if ($use_section) {
    31 c учетом текущей секции\
    32 % }
    33 % } else {
    34 в разделе\
    35 % }
    36 % if ($total > 0) {
    37 (всего: <% $total %>, показано с <% $first + 1 %> по <% ($first + $n > $total) ? $total : $first + $n %>)
    38 % }
    39 </legend>
    40
    41 % if ($total or defined($alpha) or defined($search) ) {
    42 % if ($section_access == 2) {
    43 <& "/contenido/components/new_objects_form.msn", proto => 'documents',
    44 sect_id => $owner->id,
    45 default => ($owner->default_document_class ? $owner->default_document_class : $class) &>
    46 % }
    47 <div style="font-size:75%; font-family:Arial;">
    48 <table border="0" cellspacing="0" cellpadding="2" width="100%" style="margin:4px 0 0; border:1px solid gray;">
    49 <tr bgcolor="#e0e0e0"><th colspan="4">Поиск по букве:&nbsp;&nbsp;[<a href="?id=<% $id %>" style="font-weight:normal;">сброс фильтра</a>]</th></tr>
    50 <tr><td style="font-size:75%; font-family:Arial; padding:2px 4px;">
    51 <& /inc/alpha.msn, alpha=>$alpha, params=>\%ARGS, &>
    52 </td></tr></table>
    53 % ## Форма поиска. Работает при включенном фильтре класса
    54 % ## и описанной для класса функции search_fields
    55 % ########################################################
    56 % if ( $filter{class} ) {
    57 % my $document = $filter{class}->new ($keeper);
    58 % my @fields = $document->search_fields;
    59 % if ( @fields ) {
    60 % my @props = $document->required_properties;
    61 <form action="sections.html">
    62 <table border="0" cellspacing="0" cellpadding="2" width="100%" style="margin:4px 0; border:1px solid gray;">
    63 <tr bgcolor="#e0e0e0"><th colspan="4">Поиск по полю:&nbsp;&nbsp;[<a href="?id=<% $id %>" style="font-weight:normal;">сброс фильтра</a>]</th></tr><tr>
    64 <td width="1%" nowrap style="padding:2px 0 2px 4px;"><select name="search_by">
    65 % foreach my $field ( @fields ) {
    66 % my ($prop) = grep { $_->{'attr'} eq $field } @props;
    67 % my $selected = $field eq $search_by ? ' selected' : '';
    68 <option value="<% $field %>"<% $selected %>><% ref $prop ? $prop->{'rusname'} : $field %>
    69 % }
    70 </td><td width="0">:</td>
    71 <td width="98%"><input type="text" name="search" value="<% $search %>" style="width:100%"></td>
    72 <td width="1%" style="padding:2px 4px 2px 0;"><input type="submit" value=" &raquo; " style="border:1px solid gray;"></td>
    73 </tr></table>
    74 % if ( $id ) {
    75 <input type="hidden" name="id" value="<% $id %>">
    76 % }
    77 % if ( $class ) {
    78 <input type="hidden" name="class" value="<% $class %>">
    79 % }
    80 % if ( $use_section ) {
    81 <input type="hidden" name="use_section" value="<% $use_section %>">
    82 % }
    83 </form>
    84 % }
    85 % }
    86
    87 <div style="height:5px"><spacer type="block" height="5"></div>
    88 <& /inc/pages_.msn, p=>$p, n=>$n, total=>$total, href=>'sections.html', params=>\%ARGS, &>
    89 </div>
    90
    91 <& /contenido/components/section_browse.msn, documents => \@documents, columns => \@columns, section => $owner, filter => \%filter_params, %ARGS &>
    92
    93 <div style="font-size:75%; font-family:Arial;">
    94 <& /inc/pages_.msn, p=>$p, n=>$n, total=>$total, href=>'sections.html', params=>\%ARGS, &>
    95 <div style="height:5px"><spacer type="block" height="5"></div>
    96 </div>
    97
    98 % } else {
    99 <h4 align="center"><i>---- Нет документов -----</i></h4>
    100 % }
    101 %
    102 % if ($section_access == 2) {
    103 <& "/contenido/components/new_objects_form.msn", proto => 'documents',
    104 sect_id => $owner->id,
    105 default => ($owner->default_document_class ? $owner->default_document_class : $class) &>
    106 % }
    107
    108 </fieldset>
    109 </td>
    110 </tr>
    111 </table>
    112
    113 % }
    114
    115 </body>
    116 </html>
    117 <%args>
    118
    119 $id => 1
    120 $p => 1
    121 $class => undef
    122 $use_section => undef
    123 $alpha => undef
    124 $alpha_search => undef
    125 $search_by => undef
    126 $search => undef
    127 $update => undef
    128 $delete => undef
    129
    130 </%args>
    131 <%init>
    132
    133 $id = 0 if $id =~ /\D/;
    134 my $owner;
    135
    136 # Операции...
    137 if ($id && ($id > 0))
    138 {
    139 $owner = $keeper->get_section_by_id($id);
    140 }
    141 if (! ref($owner))
    142 {
    143 return undef;
    144 }
    145
    146 $class = $state->{users}->profile_document_class;
    147 $use_section = 1 if $id != 1;
    148
    149 my %filter_params;
    150 $filter_params{use_section} = $use_section if $use_section;
    151 $filter_params{class} = $class if $class;
    152 $filter_params{alpha} = $alpha if $alpha;
    153 $filter_params{alpha_search} = $alpha_search if $alpha_search;
    154 $filter_params{search_by} = $search_by if $search_by;
    155 $filter_params{search} = $search if $search;
    156 $filter_params{p} = $p if $p > 1;
    157 $filter_params{s} = $id if $id && $id != 1;
    158
    159 # Фильтры работают в любом случае...
    160 my $filter = $m->comp('/contenido/components/context.msn', name => 'filter');
    161 my $profile = $m->comp('/contenido/components/context.msn', name => 'profile');
    162
    163 unless (defined $request->{section_accesses}->{$id})
    164 {
    165 $request->{section_accesses}->{$id} = $user->get_section_access($id);
    166 }
    167 my $section_access = $request->{section_accesses}->{$id};
    168
    169 my (@documents, $total);
    170
    171 my $s = $owner->id;
    172 my $sorted = $owner->_sorted();
    173 $s .= ",$filter" if ($filter > 0);
    174
    175 if ($update) {
    176 my $return_params = join ('&', map { $_.'='.$filter_params{$_} } grep { $_ ne 's' } keys %filter_params );
    177 my %updated;
    178 while ( my ($field, $value) = each %ARGS ) {
    179 if ( $field =~ /^update_(\d+)_(\w+)$/ ) {
    180 my $oid = $1;
    181 my $attr = $2;
    182 $updated{$oid}{$attr} = $value;
    183 }
    184 }
    185 my %classes = map { $_->{class} => 1 } values %updated;
    186 foreach my $update_class ( keys %classes ) {
    187 my @ids;
    188 while ( my ($oid, $attr) = each %updated) {
    189 push @ids, $oid if $attr->{class} eq $update_class;
    190 }
    191 my @objects = $keeper->get_documents (
    192 id => \@ids,
    193 class => $update_class
    194 ) if @ids;
    195 foreach my $object ( @objects ) {
    196 my $document_access = $user->section_accesses($user, $object->section);
    197 next unless $document_access == 2;
    198 my $fields = $updated{$object->id};
    199 my @props = grep { exists $_->{inline} && $_->{inline} } $object->structure;
    200 if ( ref $fields eq 'HASH' ) {
    201 foreach my $prop ( @props ) {
    202 my $attr = $prop->{attr};
    203 my $value = ref $fields && exists $fields->{$attr} ? $fields->{$attr} : undef;
    204 if ( $prop->{db_type} eq 'float' ) {
    205 for ( $value ) {
    206 s/\,/\./;
    207 s/^\s+//;
    208 s/\s+$//;
    209 }
    210 }
    211 if ( $prop->{type} eq 'checkbox' ) {
    212 $value = $value ? 1 : undef;
    213 }
    214
    215 $object->$attr($value);
    216 }
    217 $object->store;
    218 }
    219 }
    220 }
    221 $m->redirect("sections.html?id=".$id.($return_params ? '&'.$return_params : ''));
    222 }
    223 if ( $delete ) {
    224 my $return_params = join ('&', map { $_.'='.$filter_params{$_} } grep { $_ ne 's' } keys %filter_params );
    225 my %deleted;
    226 while ( my ($field, $value) = each %ARGS ) {
    227 if ( $field =~ /^delete_(\d+)_(\w+)$/ ) {
    228 my $oid = $1;
    229 my $attr = $2;
    230 $deleted{$oid}{$attr} = $value;
    231 }
    232 }
    233 my %classes = map { $_->{class} => 1 } values %deleted;
    234 foreach my $delete_class ( keys %classes ) {
    235 my @ids;
    236 while ( my ($oid, $attr) = each %deleted) {
    237 push @ids, $oid if exists $attr->{id} && $attr->{id} && ($attr->{class} eq $delete_class);
    238 }
    239 my @objects = $keeper->get_documents (
    240 id => \@ids,
    241 class => $delete_class
    242 ) if @ids;
    243 foreach my $object ( @objects ) {
    244 my $document_access = $user->section_accesses($user, $object->section);
    245 next unless $document_access == 2;
    246 $object->delete;
    247 }
    248 }
    249 $m->redirect("sections.html?id=".$id.($return_params ? '&'.$return_params : ''));
    250 }
    251
    252 my %filter=();
    253 my %order = (not $class and $owner->order_by) ? (order_by => $owner->order_by) : (order => ['date','direct']);
    254 if (defined $alpha and $alpha ne '') {
    255 $filter{ilike}=1;
    256 $filter{ $alpha_search || 'name' }="$alpha%";
    257 $order{order}=['name','reverse'];
    258 delete $order{order_by};
    259 }
    260
    261 $filter{class} = $owner->default_document_class if $owner->default_document_class;
    262 $filter{class} = $class if ($class);
    263 $filter{s}=$s unless ($class && !$use_section);
    264 if ( $search_by && defined $search ) {
    265 my $doc_class = $class || $owner->default_document_class;
    266 if ( $doc_class ) {
    267 my @props = $doc_class->new( $keeper )->structure();
    268 my ($prop) = grep { $_->{attr} eq $search_by } @props if @props;
    269 if ( ref $prop && $prop->{type} eq 'integer' ) {
    270 $filter{$search_by} = int($search);
    271 } else {
    272 $filter{$search_by}='%'.$search.'%';
    273 $filter{ilike} = 1;
    274 }
    275 } else {
    276 $filter{$search_by}='%'.$search.'%';
    277 $filter{ilike} = 1;
    278 }
    279 }
    280
    281 # Дополнительные фильтры раздела
    282 if ($owner->filters) {
    283 no strict 'vars';
    284 my $filters = eval($owner->filters);
    285 if ($@) {
    286 warn "Bad filter: " . $owner->filters . " in section " . $owner->id;
    287 } elsif (ref $filters eq 'HASH') {
    288 map { $filter{$_} = $filters->{$_} } keys %$filters;
    289 }
    290 }
    291
    292 $total = $keeper->get_documents(%filter, count=>1);
    293
    294 my $n = 40;
    295 my $first = $n * ($p - 1);
    296 ($first,$p)=(0,0) if ($first>$total);
    297
    298 if ($class && !$use_section) {
    299 @documents = $keeper->get_documents(%filter, %order, limit=>$n, offset=>$first);
    300 } elsif ($sorted) {
    301 @documents = $keeper->get_sorted_documents(%filter, limit=>$n, offset=>$first);
    302 } else {
    303 @documents = $keeper->get_documents(%filter, %order, limit=>$n, offset=>$first);
    304 }
    305
    306 # набор колонок таблицы документов...
    307 my @columns = $sorted ? ({attr => '_sort_', name => 'N'}) : ();
    308
    309 # пытаемся найти колонки, которые документ сам пожелал показать (required_properties -> column)...
    310 if ($filter{class} or @documents and $documents[0]) {
    311 push @columns,
    312 sort {$a->{column} <=> $b->{column}}
    313 grep {$_->{column}} ($filter{class} ? $filter{class}->new($keeper)->structure : $documents[0]->structure);
    314 }
    315
    316 # стандартная жопка таблицы...
    317 @columns = (@columns,
    318 {attr => '_act_', rusname => 'Действия'},
    319 );
    320 </%init>
  • utf8/plugins/users/comps/contenido/users/link_frame.html

     
    1 <frameset border="0" bordercolor="black" rows="40,*" frameborder="1">
    2 <frame src="links/title.html?class=<% $class %>" bordercolor="black" marginheight="2" marginwidth="2"
    3 name="linktitle" noresize scrolling="no" height="30">
    4 <frameset border="0" bordercolor="black" cols="50%,50%" frameborder="1">
    5 <frame src="links/source.html<% $sargs %>" bordercolor="gray" marginheight="2" marginwidth="2" name="sourcefrm" noresize scrolling="yes">
    6 <frame src="links/destination.html<% $dargs %>" bordercolor="black" marginheight="2" marginwidth="2" name="destfrm" noresize scrolling="yes">
    7 </frameset>
    8 </frameset>
    9
    10 <%args>
    11 $class => ''
    12 $source_class => ''
    13 $source_id => ''
    14 $dest_class => ''
    15 $dest_id => ''
    16 $save => 0
    17 $status => 0
    18 </%args>
    19 <%init>
    20
    21 my (@source_args, $sargs, @dest_args, $dargs);
    22 push @source_args, 'class='.$class if $class;
    23 push @source_args, 'source_class='.$source_class if $source_class;
    24 push @source_args, 'source_id='.$source_id if $source_id;
    25 push @dest_args, 'class='.$class if $class;
    26 push @dest_args, 'dest_class='.$dest_class if $dest_class;
    27 push @dest_args, 'dest_id='.$dest_id if $dest_id;
    28
    29 $sargs = @source_args ? '?'.join('&', @source_args) : undef;
    30 $dargs = @dest_args ? '?'.join('&', @dest_args) : undef;
    31
    32 </%init>
  • utf8/plugins/users/comps/contenido/users/links/destination.html

     
    1 <& "/contenido/components/title.msn", title=>'Создание связей' &>
    2 <style>
    3 <!--
    4 body {margin:5px;}
    5 -->
    6 </style>
    7
    8
    9 % if (ref $document) {
    10 % ### Destination is available
    11 % ######################################################
    12
    13 <script language="JavaScript">
    14 <!--
    15 function DeleteSource ()
    16 {
    17 oSelect = document.forms['sourceform'].elements[0];
    18 for (j = 0; j < oSelect.options.length; j++) {
    19 if (!oSelect.options[j].selected) {
    20 oSelect.options[j] = null;
    21 }
    22 }
    23 return true;
    24 }
    25
    26 function SelectAllSources ()
    27 {
    28 oSelect = document.forms['sourceform'].elements[0];
    29 // oSelect.setExpression('multiple', true);
    30 // document.recalc(true);
    31 for (j = 0; j < oSelect.options.length; j++) {
    32 oSelect.options[j].selected = true;
    33 }
    34 return true;
    35 }
    36
    37 function CheckSource ()
    38 {
    39 oSelect = document.forms['sourceform'].elements[0];
    40 if ( oSelect.options.length ) {
    41 return true;
    42 } else {
    43 alert ('Не выбран ни один документ');
    44 return false;
    45 }
    46 }
    47
    48 //-->
    49 </script>
    50
    51 %
    52 % my @properties = $document->structure();
    53 % my ($prop) = grep { $_->{'attr'} eq 'status' } @properties;
    54 % my ($status) = grep { $_->[0] == $document->status } @{ $m->comp( '/contenido/components/inputs/status.msn', prop => $prop, object=>$document, name => $prop->{attr}, mode => 'get') };
    55 % $status = $status->[1];
    56 <table width="100%" border="0" align="center"><tr><td>
    57 <fieldset>
    58 <legend>Цель</legend>
    59 <table class="tform" width="100%">
    60 <tr valign="top"><td><b>Название:</b>
    61 </td><td><a href="/contenido/document.html?id=<% $document->id %>&class=<% $document->class %>" target="_top"><% $document->name %></a>
    62 </td></tr>
    63 <tr valign="top"><td><b>Класс:</b>
    64 </td><td><% $document->class %>
    65 </td></tr>
    66 <tr valign="top"><td><b>Статус:</b>
    67 </td><td><% $status %>
    68 </td></tr>
    69 </table>
    70 </fieldset>
    71
    72 <fieldset>
    73 <legend>Список связей</legend>
    74 <table class="tform" width="100%">
    75 <tr><td>
    76 <form action="link_add.html" name="sourceform" target="_top" method="post" onsubmit="return CheckSource();">
    77 <select multiple name="sources" size="20" style="width:100%">
    78 </select>
    79 <p>К данной цели будут привязаны только выделенные документы.</p>
    80 <input type="hidden" name="class" value="<% $class %>">
    81 <input type="hidden" name="dest_id" value="<% $dest_id %>">
    82 <input type="hidden" name="dest_class" value="<% $dest_class %>">
    83 <input type="button" value="Выделить все" onclick="SelectAllSources();">
    84 <input type="button" value="Удалить лишнее" onclick="DeleteSource();">
    85 <input type="submit" value="Связать выбранное">
    86 </form>
    87 </td></tr>
    88 </table>
    89 </fieldset>
    90
    91 </td></tr></table>
    92
    93
    94 % }else{
    95 % ### Destination is not available
    96 % ######################################################
    97 %
    98
    99 <script language="JavaScript">
    100 <!--
    101 function AddDest (Value, Name)
    102 {
    103 // alert (Name);
    104
    105 var oSelect = parent.frames.sourcefrm.document.forms['destform'].elements[0];
    106 var Found = 0;
    107 for(j=0; j < oSelect.options.length; j++) {
    108 if (oSelect.options[j].value == Value) {
    109 Found = 1;
    110 }
    111 }
    112 if (!Found) {
    113 var oOption = document.createElement("OPTION");
    114 oOption.text=Name;
    115 oOption.value=Value;
    116 oOption.selected=true;
    117 oSelect.options.add(oOption);
    118 }
    119 return false;
    120 }
    121 //-->
    122 </script>
    123
    124 <& /contenido/components/link_browse.msn,
    125 class => $class,
    126 dest_class => $dest_class,
    127 p => $p,
    128 use_section => $use_section,
    129 alpha => $alpha,
    130 alpha_search => $alpha_search,
    131 search => $search,
    132 search_by => $search_by,
    133 restrict_class => $restrict_class,
    134 &>
    135
    136 % }
    137
    138 </body>
    139 </html>
    140 <%args>
    141
    142 $class => ''
    143 $source_class => ''
    144 $source_id => ''
    145 $dest_class => ''
    146 $dest_id => ''
    147 $save => 0
    148 $status => 0
    149
    150 $p => 1
    151 $restrict_class => undef
    152 $use_section => undef
    153 $alpha => undef
    154 $alpha_search => undef
    155 $search_by => undef
    156 $search => undef
    157
    158 </%args>
    159 <%init>
    160
    161 my $document;
    162
    163 if ($dest_id) {
    164 $document = $keeper->get_document_by_id ($dest_id,
    165 class => $dest_class,
    166 );
    167 } else {
    168 $dest_class = $class->available_destinations;
    169 }
    170
    171 </%init>
  • utf8/plugins/users/comps/contenido/users/links/link_add.html

     
    1 %#<pre><% Dumper(\%ARGS) %></pre>
    2 <%args>
    3
    4 $class => undef
    5 $source_id => undef
    6 $source_class => undef
    7 $dest_id => undef
    8 $dest_class => undef
    9 $sources => undef
    10 $destinations => undef
    11
    12 </%args>
    13 <%init>
    14
    15 abort404 unless $class;
    16
    17 my @documents;
    18 my $ret_params;
    19 if ( $source_id && $source_class && ($destinations || (ref $destinations eq 'ARRAY' && @$destinations)) ) {
    20 @documents = $keeper->get_documents (
    21 in_id => $destinations,
    22 );
    23 foreach my $doc (@documents) {
    24 my $link = $class->new ($keeper);
    25 $link->source_id ($source_id);
    26 $link->source_class ($source_class);
    27 $link->dest_id ($doc->id);
    28 $link->dest_class ($doc->class);
    29 $link->store;
    30 }
    31 $ret_params = "id=$source_id&class=$source_class";
    32 } elsif ( $dest_id && $dest_class && ($sources || (ref $sources eq 'ARRAY' && @$sources)) ) {
    33 @documents = $keeper->get_documents (
    34 in_id => $sources,
    35 );
    36 foreach my $doc (@documents) {
    37 my $link = $class->new ($keeper);
    38 $link->dest_id ($dest_id);
    39 $link->dest_class ($dest_class);
    40 $link->source_id ($doc->id);
    41 $link->source_class ($doc->class);
    42 $link->store;
    43 }
    44 $ret_params = "id=$dest_id&class=$dest_class";
    45 }
    46 if ($ret_params) {
    47 $m->redirect("Location", "/contenido/users/document.html?".$ret_params);
    48 }else{
    49 &abort404;
    50 }
    51
    52 </%init>
  • utf8/plugins/users/comps/contenido/users/links/source.html

     
    1 <& "/contenido/components/title.msn", title=>'Создание связей' &>
    2 <style>
    3 <!--
    4 body {margin:5px;}
    5 -->
    6 </style>
    7
    8 % if (ref $document) {
    9 % ### Source is available
    10 % ######################################################
    11
    12 <script language="JavaScript">
    13 <!--
    14 function DeleteDest ()
    15 {
    16 oSelect = document.forms['destform'].elements[0];
    17 for (j = 0; j < oSelect.options.length; j++) {
    18 if (!oSelect.options[j].selected) {
    19 oSelect.options[j] = null;
    20 }
    21 }
    22 return true;
    23 }
    24
    25 function SelectAllDest ()
    26 {
    27 oSelect = document.forms['destform'].elements[0];
    28 // oSelect.setExpression('multiple', true);
    29 // document.recalc(true);
    30 for (j = 0; j < oSelect.options.length; j++) {
    31 oSelect.options[j].selected = true;
    32 }
    33 return true;
    34 }
    35
    36 function CheckDest ()
    37 {
    38 oSelect = document.forms['destform'].elements[0];
    39 if ( oSelect.options.length ) {
    40 return true;
    41 } else {
    42 alert ('Не выбран ни один документ');
    43 return false;
    44 }
    45 }
    46
    47 //-->
    48 </script>
    49
    50 %
    51 % my @properties = $document->structure();
    52 % my ($prop) = grep { $_->{'attr'} eq 'status' } @properties;
    53 % my ($status) = grep { $_->[0] == $document->status } @{ $m->comp( '/contenido/components/inputs/status.msn', prop => $prop, object=>$document, name => $prop->{attr}, mode => 'get') };
    54 % $status = $status->[1];
    55 <table width="100%" border="0" align="center"><tr><td>
    56 <fieldset>
    57 <legend>Источник</legend>
    58 <table class="tform" width="100%">
    59 <tr valign="top"><td><b>Название:</b>
    60 </td><td><a href="/contenido/document.html?id=<% $document->id %>&class=<% $document->class %>" target="_top"><% $document->name %></a>
    61 </td></tr>
    62 <tr valign="top"><td><b>Класс:</b>
    63 </td><td><% $document->class %>
    64 </td></tr>
    65 <tr valign="top"><td><b>Статус:</b>
    66 </td><td><% $status %>
    67 </td></tr>
    68 </table>
    69 </fieldset>
    70
    71 <fieldset>
    72 <legend>Список связей</legend>
    73 <table class="tform" width="100%">
    74 <tr><td>
    75 <form action="link_add.html" name="destform" target="_top" method="post" onsubmit="return CheckDest();">
    76 <select multiple name="destinations" size="20" style="width:100%">
    77 </select>
    78 <p>К источнику будут привязаны только выделенные документы.</p>
    79 <input type="hidden" name="class" value="<% $class %>">
    80 <input type="hidden" name="source_id" value="<% $source_id %>">
    81 <input type="hidden" name="source_class" value="<% $source_class %>">
    82 <input type="button" value="Выделить все" onclick="SelectAllDest();">
    83 <input type="button" value="Удалить лишнее" onclick="DeleteDest();">
    84 <input type="submit" value="Связать выбранное">
    85 </form>
    86 </td></tr>
    87 </table>
    88 </fieldset>
    89
    90 </td></tr></table>
    91
    92 %#<pre><% Dumper(\@properties) %></pre>
    93
    94 % }else{
    95 % ### Source is not available
    96 % ######################################################
    97 %
    98
    99 <script language="JavaScript">
    100 <!--
    101 function AddSource (Value, Name)
    102 {
    103 // alert (Name);
    104
    105 var oSelect = parent.frames.destfrm.document.forms['sourceform'].elements[0];
    106 var Found = 0;
    107 for(j=0; j < oSelect.options.length; j++) {
    108 if (oSelect.options[j].value == Value) {
    109 Found = 1;
    110 }
    111 }
    112 if (!Found) {
    113 var oOption = document.createElement("OPTION");
    114 oOption.text=Name;
    115 oOption.value=Value;
    116 oOption.selected=true;
    117 oSelect.options.add(oOption);
    118 }
    119 return false;
    120 }
    121 //-->
    122 </script>
    123
    124 <& /contenido/components/link_browse.msn,
    125 class => $class,
    126 source_class => $source_class,
    127 p => $p,
    128 use_section => $use_section,
    129 alpha => $alpha,
    130 alpha_search => $alpha_search,
    131 search => $search,
    132 search_by => $search_by,
    133 restrict_class => $restrict_class,
    134 &>
    135
    136 % }
    137
    138 </body>
    139 </html>
    140 <%args>
    141 $class => ''
    142 $source_class => ''
    143 $source_id => ''
    144 $dest_class => ''
    145 $dest_id => ''
    146 $save => 0
    147 $status => 0
    148
    149 $p => 1
    150 $restrict_class => undef
    151 $use_section => undef
    152 $alpha => undef
    153 $alpha_search => undef
    154 $search_by => undef
    155 $search => undef
    156
    157 </%args>
    158 <%init>
    159
    160 my $document;
    161
    162 if ($source_id) {
    163 $document = $keeper->get_document_by_id ($source_id,
    164 class => $source_class,
    165 );
    166 } else {
    167 $source_class = $class->available_sources;
    168 }
    169
    170 </%init>
  • utf8/plugins/users/comps/contenido/users/links/title.html

     
    1 <& "/contenido/components/title.msn", title=>'Создание связей' &>
    2 <table width="100%" cellspacing="5" cellpadding="0" border="0">
    3 <tr><td style="font-size:110%;">
    4 <div><b>Создание связей. Тип связи&nbsp; &mdash;
    5 &nbsp; <% $class->class_name %> (<span style="color:olive;"><% $class %></span>)</b></div>
    6 </td></tr>
    7 </table>
    8 </body>
    9 </html>
    10 <%args>
    11 $class => ''
    12 $source_class => ''
    13 $source_id => ''
    14 $dest_class => ''
    15 $dest_id => ''
    16 $save => 0
    17 $status => 0
    18 </%args>
  • utf8/plugins/users/comps/contenido/users/store_document_sections.html

     
    1 <%ARGS>
    2 $id => undef
    3 $class => undef
    4 </%ARGS>
    5
    6 <%INIT>
    7 if ($id)
    8 {
    9 my $document = $keeper->get_document_by_id($id, class=>$class);
    10
    11 my %sections = ();
    12 foreach my $name (keys %ARGS)
    13 {
    14 if ($name =~ /^section_(\d+)$/)
    15 {
    16 $sections{$1} = 1;
    17 }
    18 }
    19 my @sections_in_order = ();
    20 if ($ARGS{main_section} > 0)
    21 {
    22 delete $sections{ $ARGS{main_section} };
    23 push (@sections_in_order, $ARGS{main_section});
    24 }
    25 push (@sections_in_order, keys(%sections));
    26
    27 $document->sections(@sections_in_order);
    28 $document->store();
    29
    30 $r->header_out("Location", "document.html?id=$id&class=$class");
    31 $r->status(302);
    32 $r->send_http_header();
    33 $m->abort();
    34 }
    35
    36 </%init>
  • utf8/plugins/users/config.proto

     
    1 #############################################################################
    2 #
    3 # Параметры данного шаблона необходимо ВРУЧНУЮ добавить в config.mk проекта
    4 # и привести в соответствие с требованиями проекта
    5 #
    6 #############################################################################
    7
    8 PLUGINS += users
    9
    10 PROFILE_DOCUMENT_CLASS = MyProject::Profile
    11 REWRITE += PROFILE_DOCUMENT_CLASS
    12
    13 PROFILE_AUTH_METHOD = LDAP
    14 LDAP_LOGIN = <Full LDAP DSN>
    15 LDAP_PASSWORD = <LDAP Password>
    16 REWRITE += PROFILE_AUTH_METHOD LDAP_LOGIN LDAP_PASSWORD
    17
    18 PROFILE_AUTH_METHOD = RPC
    19 REWRITE += PROFILE_AUTH_METHOD
    20
    21
    22 ########################################################################
    23 #
    24 # PROFILE_DOCUMENT_CLASS
    25 # Добавляется при перекрытии стандартного класса users::Profile
    26 # классом из проекта. В этом случае все методы будут дергать
    27 # проектный класс
    28 # PROFILE_AUTH_METHOD
    29 # Метод авторизации. Если не указать, будет использоваться
    30 # локальная авторизация. Варианты: LDAP, RPC
    31 # LDAP_LOGIN и LDAP_PASSWORD
    32 # Параметры учетной записи в LDAP, с помощью которой осуществляется
    33 # поиск и авторизация всех пользователей.
    34 #
    35 ########################################################################
  • utf8/plugins/users/lib/users/Apache.pm

     
    1 package users::Apache;
    2
    3 use strict;
    4 use warnings 'all';
    5
    6 use users::State;
    7 use Contenido::Globals;
    8
    9
    10 sub child_init {
    11 # встраиваем keeper плагина в keeper проекта
    12 $keeper->{users} = users::Keeper->new($state->users);
    13 }
    14
    15 sub request_init {
    16 }
    17
    18 sub child_exit {
    19 }
    20
    21 1;
  • utf8/plugins/users/lib/users/Init.pm

     
    1 package users::Init;
    2
    3 use strict;
    4 use warnings 'all';
    5
    6 use Contenido::Globals;
    7 use users::Apache;
    8 use users::Keeper;
    9
    10
    11 # загрузка всех необходимых плагину классов
    12 # users::SQL::SomeTable
    13 # users::SomeClass
    14 Contenido::Init::load_classes(qw(
    15 users::SQL::UserProfile
    16
    17 users::UserProfile
    18 users::Section
    19 ));
    20
    21 sub init {
    22 push @{ $state->{'available_documents'} }, 'users::UserProfile' if $state->{users}->profile_document_class eq 'users::UserProfile';
    23 push @{ $state->{'available_sections'} }, 'users::Section';
    24 0;
    25 }
    26
    27 1;
  • utf8/plugins/users/lib/users/Keeper.pm

     
    1 package users::Keeper;
    2
    3 use strict;
    4 use warnings 'all';
    5 use base qw(Contenido::Keeper);
    6
    7 use Digest::MD5;
    8 use Contenido::Globals;
    9 use Data::Dumper;
    10
    11 # ----------------------------------------------------------------------------
    12 # Функции:
    13 # ----------------------------------------------------------------------------
    14 # check_login: Наличие пользователя в системе
    15 #
    16 # login => login пользователя
    17 # email => email пользователя
    18 # ----------------------------------------------------------------------------
    19 sub check_login {
    20
    21 my $self = shift;
    22 my %opts = @_;
    23
    24 return if !$opts{login} && !$opts{email};
    25 my $class = $self->state->profile_document_class;
    26 my $res = $keeper->get_documents (
    27 class => $class,
    28 $opts{login} ? (login => $opts{login}) : (),
    29 $opts{email} ? (email => lc($opts{email})) : (),
    30 count => 1,
    31 );
    32 return int($res);
    33 }
    34
    35
    36
    37 # ----------------------------------------------------------------------------
    38 # login: Авторизация пользователя
    39 #
    40 # login => login пользователя
    41 # email => e-mail пользователя
    42 # passwd => пароль пользователя
    43 # ----------------------------------------------------------------------------
    44 sub login {
    45
    46 my $self = shift;
    47 my %opts = @_;
    48
    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 );
    72 }
    73 return $res;
    74 }else{
    75 return;
    76 }
    77
    78 }
    79
    80
    81
    82 # ----------------------------------------------------------------------------
    83 # confirm: Подтверждение аутентификации
    84 #
    85 # login => login пользователя
    86 # email => e-mail пользователя
    87 # md5 => MD5 пароля пользователя
    88 # ----------------------------------------------------------------------------
    89 sub confirm {
    90
    91 my $self = shift;
    92 my %opts = @_;
    93
    94 return if !($opts{login} || $opts{email}) && !$opts{md5};
    95 my $class = $self->state->profile_document_class;
    96 my $res = $keeper->get_documents (
    97 class => $class,
    98 $opts{login} ? (login => $opts{login}) : (),
    99 $opts{email} ? (email => lc($opts{email})) : (),
    100 return_mode => 'array_ref',
    101 );
    102 $res = ref $res eq 'ARRAY' && scalar @$res ? $res->[0] : undef;
    103 return unless ref $res;
    104 warn "MD5 = ".$opts{md5}."; user MD5 = ".$res->passwd."\n" if $DEBUG;
    105 if ($res->passwd eq $opts{md5} ) {
    106 my $now = localtime;
    107 $res->lastlogin( $now );
    108 $res->passwd(undef);
    109 $res->status(1);
    110 $res->store;
    111 return $res;
    112 }else{
    113 return;
    114 }
    115
    116 }
    117
    118
    119
    120 # ----------------------------------------------------------------------------
    121 # get_profile: Вытащить профиль пользователя
    122 #
    123 # id => по ID
    124 # login => по login
    125 # email => по e-mail
    126 # nickname=> по никнейму
    127 # status => фильтр по статусу
    128 # ----------------------------------------------------------------------------
    129 sub get_profile {
    130
    131 my $self = shift;
    132 my %opts = @_;
    133
    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 (
    137 class => $class,
    138 %opts,
    139 return_mode => 'array_ref',
    140 );
    141 $res = ref $res eq 'ARRAY' && scalar @$res ? $res->[0] : undef;
    142 return $res;
    143 }
    144
    145 1;
  • utf8/plugins/users/lib/users/Section.pm

     
    1 package users::Section;
    2
    3 use Contenido::Section;
    4 @ISA = ('Contenido::Section');
    5
    6 sub extra_properties
    7 {
    8 return (
    9 )
    10 }
    11
    12 sub class_name
    13 {
    14 return 'Секция пользовательских профилей';
    15 }
    16
    17 sub class_description
    18 {
    19 return 'Секция пользовательских профилей';
    20 }
    21
    22
    23 1;
  • utf8/plugins/users/lib/users/SQL/UserProfile.pm

     
    1 package users::SQL::UserProfile;
    2
    3 use base 'SQL::DocumentTable';
    4
    5 sub db_table
    6 {
    7 return 'profiles';
    8 }
    9
    10 my $available_filters = [qw(
    11
    12 _class_filter
    13 _status_filter
    14 _in_id_filter
    15 _id_filter
    16 _name_filter
    17 _class_excludes_filter
    18 _sfilter_filter
    19 _excludes_filter
    20 _datetime_filter
    21 _date_equal_filter
    22 _date_filter
    23 _previous_days_filter
    24 _s_filter
    25
    26 _login_filter
    27 _email_filter
    28 _nickname_filter
    29 )];
    30
    31 sub available_filters {
    32 return $available_filters;
    33 }
    34
    35 my @required_properties = (
    36 { # Идентификатор документа, сквозной по всем типам...
    37 'attr' => 'id',
    38 'type' => 'integer',
    39 'rusname' => 'Идентификатор документа',
    40 'hidden' => 1,
    41 'readonly' => 1,
    42 'auto' => 1,
    43 'db_field' => 'id',
    44 'db_type' => 'integer',
    45 'db_opts' => "not null default nextval('public.documents_id_seq'::text)",
    46 },
    47 { # Класс документа...
    48 'attr' => 'class',
    49 'type' => 'string',
    50 'rusname' => 'Класс документа',
    51 'hidden' => 1,
    52 'readonly' => 1,
    53 'db_field' => 'class',
    54 'db_type' => 'varchar(48)',
    55 'db_opts' => 'not null',
    56 },
    57 { # Ф.И.О....
    58 'attr' => 'name',
    59 'type' => 'string',
    60 'rusname' => 'Ф.И.О.',
    61 'column' => 2,
    62 'db_field' => 'name',
    63 'db_type' => 'varchar(255)',
    64 },
    65 { # Время создания документа, служебное поле...
    66 'attr' => 'ctime',
    67 'type' => 'datetime',
    68 'rusname' => 'Время создания',
    69 'readonly' => 1,
    70 'auto' => 1,
    71 'hidden' => 1,
    72 'db_field' => 'ctime',
    73 'db_type' => 'timestamp',
    74 'db_opts' => 'not null default now()',
    75 'default' => 'CURRENT_TIMESTAMP',
    76 },
    77 { # Время модификации документа, служебное поле...
    78 'attr' => 'mtime',
    79 'type' => 'datetime',
    80 'rusname' => 'Время модификации',
    81 'hidden' => 1,
    82 'auto' => 1,
    83 'db_field' => 'mtime',
    84 'db_type' => 'timestamp',
    85 'db_opts' => 'not null default now()',
    86 'default' => 'CURRENT_TIMESTAMP',
    87 },
    88 { # Дата рождения
    89 'attr' => 'dtime',
    90 'type' => 'date',
    91 'rusname' => 'Дата рождения',
    92 'db_field' => 'dtime',
    93 'db_type' => 'timestamp',
    94 'default' => 'CURRENT_TIMESTAMP',
    95 },
    96 { # Дата и время логина...
    97 'attr' => 'lastlogin',
    98 'type' => 'datetime',
    99 'rusname' => 'Дата и время последнего логина<sup style="color:#888;">&nbsp;1)</sup>',
    100 'column' => 1,
    101 'db_field' => 'lastlogin',
    102 'db_type' => 'timestamp',
    103 'db_opts' => 'not null default now()',
    104 'default' => 'CURRENT_TIMESTAMP',
    105 },
    106 { # Массив секций, обрабатывается специальным образом...
    107 'attr' => 'sections',
    108 'type' => 'sections_list',
    109 'rusname' => 'Секции',
    110 'hidden' => 1,
    111 'db_field' => 'sections',
    112 'db_type' => 'integer[]',
    113 },
    114 { # Одно поле статуса является встроенным...
    115 'attr' => 'status',
    116 'type' => 'status',
    117 'rusname' => 'Статус',
    118 'db_field' => 'status',
    119 'db_type' => 'integer',
    120 },
    121 { # Дополнительное поле статуса
    122 'attr' => 'type',
    123 'type' => 'integer',
    124 'rusname' => 'Тип пользователя (project-oriented)',
    125 'db_field' => 'type',
    126 'db_type' => 'integer',
    127 },
    128 { # Никнейм...
    129 'attr' => 'nickname',
    130 'type' => 'string',
    131 'rusname' => 'Ник',
    132 'column' => 3,
    133 'db_field' => 'nickname',
    134 'db_type' => 'text',
    135 },
    136 { # Login...
    137 'attr' => 'login',
    138 'type' => 'string',
    139 'rusname' => 'Логин',
    140 'column' => 4,
    141 'db_field' => 'login',
    142 'db_type' => 'text',
    143 },
    144 { # Login method...
    145 'attr' => 'login_method',
    146 'type' => 'string',
    147 'rusname' => 'Метод входа',
    148 'db_field' => 'login_method',
    149 'db_type' => 'text',
    150 },
    151 { # E-mail...
    152 'attr' => 'email',
    153 'type' => 'string',
    154 'rusname' => 'E-mail (primary)',
    155 'db_field' => 'email',
    156 'db_type' => 'text',
    157 },
    158
    159 );
    160
    161 # ----------------------------------------------------------------------------
    162 # Свойства храним в массивах, потому что порядок важен!
    163 # Это общие свойства - одинаковые для всех документов.
    164 #
    165 # attr - обязательный параметр, название атрибута;
    166 # type - тип аттрибута, требуется для отображдения;
    167 # rusname - русское название, опять же требуется для отображения;
    168 # hidden - равен 1, когда
    169 # readonly - инициализации при записи только без изменения в дальнейшем
    170 # db_field - поле в таблице
    171 # default - значение по умолчанию (поле всегда имеет это значение)
    172 # ----------------------------------------------------------------------------
    173 sub required_properties
    174 {
    175 return @required_properties;
    176 }
    177
    178 ########### FILTERS DESCRIPTION ####################################################################################
    179 sub _login_filter {
    180 my ($self,%opts)=@_;
    181 return undef unless ( exists($opts{login}) );
    182 if (exists $opts{ilike} && $opts{ilike} == 1) {
    183 return &SQL::Common::_generic_name_filter('d.login', $opts{login}, 0, \%opts);
    184 }else{
    185 return &SQL::Common::_generic_text_filter('d.login', $opts{login});
    186 }
    187 }
    188
    189 sub _email_filter {
    190 my ($self,%opts)=@_;
    191 return undef unless ( exists($opts{email}) );
    192 if (exists $opts{ilike} && $opts{ilike} == 1) {
    193 return &SQL::Common::_generic_name_filter('d.email', $opts{email}, 0, \%opts);
    194 }else{
    195 return &SQL::Common::_generic_text_filter('d.email', $opts{email});
    196 }
    197 }
    198
    199 sub _nickname_filter {
    200 my ($self,%opts)=@_;
    201 return undef unless ( exists($opts{nickname}) );
    202 if (exists $opts{ilike} && $opts{ilike} == 1) {
    203 return &SQL::Common::_generic_name_filter('d.nickname', $opts{nickname}, 0, \%opts);
    204 }else{
    205 return &SQL::Common::_generic_text_filter('d.nickname', $opts{nickname});
    206 }
    207 }
    208
    209 1;
  • utf8/plugins/users/lib/users/State.pm.proto

     
    1 package users::State;
    2
    3 use strict;
    4 use warnings 'all';
    5 use vars qw($AUTOLOAD);
    6
    7
    8 sub new {
    9 my ($proto) = @_;
    10 my $class = ref($proto) || $proto;
    11 my $self = {};
    12 bless $self, $class;
    13
    14 # зашитая конфигурация плагина
    15 $self->{db_type} = 'none';
    16 $self->{db_keepalive} = 0;
    17 $self->{db_host} = '';
    18 $self->{db_name} = '';
    19 $self->{db_user} = '';
    20 $self->{db_password} = '';
    21 $self->{db_port} = '';
    22 $self->{profile_document_class} = '@PROFILE_DOCUMENT_CLASS@' || 'users::UserProfile';
    23
    24 $self->{data_directory} = '';
    25 $self->{images_directory} = '';
    26 $self->{binary_directory} = '';
    27 $self->{preview} = '';
    28 $self->{debug} = '';
    29 $self->{store_method} = '';
    30 $self->{cascade} = '';
    31 $self->{memcached_enable} = '';
    32
    33 $self->_init_();
    34 $self;
    35 }
    36
    37 sub info {
    38 my $self = shift;
    39 return unless ref $self;
    40
    41 for (sort keys %{$self->{attributes}}) {
    42 my $la = length $_;
    43 warn "\t$_".("\t" x (2-int($la/8))).": $self->{$_}\n";
    44 }
    45 }
    46
    47 sub _init_ {
    48 my $self = shift;
    49
    50 # зашитая конфигурация плагина
    51 $self->{attributes}->{$_} = 'SCALAR' for qw(
    52 db_type
    53 profile_document_class
    54 db_keepalive
    55 db_host
    56 db_port
    57 db_name
    58 db_user
    59 db_password
    60 data_directory images_directory binary_directory preview debug store_method cascade memcached_enable
    61 );
    62 }
    63
    64 sub AUTOLOAD {
    65 my $self = shift;
    66 my $attribute = $AUTOLOAD;
    67
    68 $attribute =~ s/.*:://;
    69 return unless $attribute =~ /[^A-Z]/; # Отключаем методы типа DESTROY
    70
    71 if (!exists $self->{attributes}->{$attribute}) {
    72 warn "Contenido Error (users::State): Вызов метода, для которого не существует обрабатываемого свойства: ->$attribute()\n";
    73 return;
    74 }
    75
    76 $self->{$attribute} = shift @_ if $#_>=0;
    77 $self->{$attribute};
    78 }
    79
    80 1;
  • utf8/plugins/users/lib/users/UserProfile.pm

     
    1 package users::UserProfile;
    2
    3 use base "Contenido::Document";
    4 use Digest::MD5;
    5 use Contenido::Globals;
    6
    7 sub extra_properties
    8 {
    9 return (
    10 { 'attr' => 'status', 'type' => 'status', 'rusname' => 'Статус пользователя',
    11 'cases' => [
    12 [0, 'Блокированный'],
    13 [1, 'Активный'],
    14 [2, 'Платный'],
    15 [3, 'Свой/сотрудник'],
    16 [4, 'VIP'],
    17 [5, 'Временная активация'],
    18 ],
    19 },
    20 { 'attr' => 'visibility', 'type' => 'status', 'rusname' => 'Область видимости',
    21 'cases' => [
    22 [0, 'Данные моего аккаунта видны только мне'],
    23 [1, 'Данные моего аккаунта видны всем'],
    24 [2, 'Данные моего аккаунта видны друзьям'],
    25 [3, 'Данные моего аккаунта видны друзьям и членам клубов'],
    26 ],
    27 },
    28 { 'attr' => 'country', 'type' => 'string', 'rusname' => 'Страна' },
    29 { 'attr' => 'passwd', 'type' => 'password', 'rusname' => 'Пароль', 'rem' => '(<font color="red">Не отображается. Указывать при создании и для изменения</font>)' },
    30 { 'attr' => 'confirm', 'type' => 'string', 'rusname' => 'Код подтверждения', hidden => 1 },
    31 { 'attr' => 'secmail', 'type' => 'string', 'rusname' => 'E-mail (secondary)' },
    32 { 'attr' => 'q1', 'type' => 'string', 'rusname' => 'Контрольный вопрос 1' },
    33 { 'attr' => 'a1', 'type' => 'string', 'rusname' => 'Контрольный ответ 1' },
    34 { 'attr' => 'q2', 'type' => 'string', 'rusname' => 'Контрольный вопрос 2' },
    35 { 'attr' => 'a2', 'type' => 'string', 'rusname' => 'Контрольный ответ 2' },
    36 { 'attr' => 'account', 'type' => 'string', 'rusname' => 'Сумма на счете' },
    37 { 'attr' => 'interests', 'type' => 'text', 'rusname' => 'Жизненные интересы', rows => 10 },
    38 { 'attr' => 'origin', 'type' => 'text', 'rusname' => 'Ориджин', rows => 4 },
    39 { 'attr' => 'avatar', 'type' => 'image', 'rusname' => 'Аватар', preview => ['32x32','100x100','120x120','160x160'] },
    40 )
    41 }
    42
    43 sub class_name
    44 {
    45 return 'Профиль пользователя';
    46 }
    47
    48 sub class_description
    49 {
    50 return 'Профиль пользователя';
    51 }
    52
    53 sub search_fields
    54 {
    55 return ('email', 'name', 'login');
    56 }
    57
    58 sub class_table
    59 {
    60 return 'users::SQL::UserProfile';
    61 }
    62
    63 sub contenido_status_style
    64 {
    65 my $self = shift;
    66 if ( $self->status == 2 ) {
    67 return 'color:green;';
    68 } elsif ( $self->status == 3 ) {
    69 return 'color:olive;';
    70 } elsif ( $self->status == 4 ) {
    71 return 'color:green;';
    72 } elsif ( $self->status == 5 ) {
    73 return 'color:red;';
    74 }
    75 }
    76
    77 sub pre_store
    78 {
    79 my $self = shift;
    80
    81 my $up = $self->{keeper}->get_document_by_id ( $self->id,
    82 class => $self->class,
    83 );
    84 if ( (ref $up && $self->passwd && $self->passwd ne $up->passwd) || (!ref $up && $self->passwd) ) {
    85 warn "Pass = ".$self->passwd."\n" if $DEBUG;
    86 my $pass = Digest::MD5::md5_hex($self->passwd);
    87 warn "Pass_hex = $pass\n" if $DEBUG;
    88 $self->passwd($pass);
    89 } elsif ( ref $up && (!$self->passwd || $self->passwd eq $up->passwd ) ) {
    90 $self->passwd($up->passwd);
    91 }
    92 $self->email(lc($self->email));
    93 $self->login(lc($self->login));
    94
    95 my $default_section = $project->s_alias->{users} if ref $project->s_alias eq 'HASH' && exists $project->s_alias->{users};
    96 if ( $default_section ) {
    97 my $sections = $self->{sections};
    98 if ( ref $sections eq 'ARRAY' && scalar @$sections ) {
    99 my @new_sects = grep { $_ != $default_section } @$sections;
    100 push @new_sects, $default_section;
    101 $self->sections(@new_sects);
    102 } elsif ( $sections && !ref $sections && $sections != $default_section ) {
    103 my @new_sects = ($default_section, $sections);
    104 $self->sections(@new_sects);
    105 } else {
    106 $self->sections($default_section);
    107 }
    108 }
    109
    110 return 1;
    111 }
    112 1;
  • utf8/plugins/users/sql/TOAST/profiles.sql

     
    1 create table profiles
    2 (
    3 id integer not null primary key default nextval('public.documents_id_seq'::text),
    4 class text not null,
    5 ctime timestamp not null default now(),
    6 mtime timestamp not null default now(),
    7 dtime timestamp,
    8 lastlogin timestamp not null default now(),
    9 status smallint not null default 0,
    10 type integer,
    11 sections integer[],
    12 name text,
    13 nickname text,
    14 login text,
    15 email text,
    16 login_method text default 'local',
    17 data text
    18 );
    19 create index profiles_sections on profiles using gist ( "sections" "gist__int_ops" );
    20 create index profiles_lastlogin on profiles (lastlogin);
    21 create unique index profiles_login on profiles (login) where login is not null and login != '';
    22 create unique index profiles_email on profiles (email) where email is not null and email != '';

Небольшая справка по веткам

cnddist – контейнер, в котором хранятся все дистрибутивы всех библиотек и программных пакетов, которые использовались при построении различных версий Contenido. Если какой-то библиотеки в данном хранилище нет, инсталлятор сделает попытку "подтянуть" ее с веба (например, с CPAN). Если библиотека слишком старая, есть очень большая вероятность, что ее там уже нет. Поэтому мы храним весь хлам от всех сборок. Если какой-то дистрибутив вдруг отсутствует в cnddist - напишите нам, мы положим его туда.

koi8 – отмирающая ветка, чей код, выдача и все внутренние библиотеки заточены на кодировку KOI8-R. Вносятся только те дополнения, которые касаются внешнего вида и функционала админки, баги ядра, обязательные обновления портов и мелочи, которые легко скопипастить. В дальнейшем планируется полная остановка поддержки по данной ветке.

utf8 – актуальная ветка, заточенная под UTF-8.

Внутри каждой ветки: core – исходники ядра; install – скрипт установки инсталляции; plugins – плагины; samples – "готовые к употреблению" проекты, которые можно поставить, запустить и посмотреть, как они работают.