Revision 234

Date:
2012/08/28 09:26:59
Author:
ahitrov
Revision Log:
Blog plugin
Files:

Legend:

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

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

     
    1 <& $call, %ARGS &>
    2 <%init>
    3
    4 my $call;
    5 if ( $r->uri eq '/contenido/blogs/' ) {
    6 $call = 'index.html';
    7 } else {
    8 &abort404;
    9 }
    10
    11 </%init>
  • utf8/plugins/blogs/comps/contenido/blogs/index.html

     
    1 <& "/contenido/components/header.msn" &>
    2 <& "/contenido/components/naviline.msn" &>
    3
    4 <p>PLugin [blogs]</p>
    5
    6 </body>
    7 </html>
  • utf8/plugins/blogs/lib/blogs/Apache.pm

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

     
    1 package blogs::Blog;
    2
    3 use base "Contenido::Document";
    4 use Contenido::Globals;
    5
    6 sub extra_properties
    7 {
    8 return (
    9 { 'attr' => 'status', 'type' => 'status', 'rusname' => 'Статус чтения/комментирования',
    10 'cases' => [
    11 [0, 'Заблокирован'],
    12 [1, 'Открыт для комментирования всеми'],
    13 [2, 'Открыт для комментирования членами сообщества'],
    14 [3, 'Открыт только для чтения'],
    15 ],
    16 },
    17 { 'attr' => 'type', 'type' => 'status', 'rusname' => 'Статус записи',
    18 'cases' => [
    19 [0, 'Личный блог'],
    20 [1, 'Блог сообщества'],
    21 [2, 'Публичный блог'],
    22 [3, 'Системный блог (contenido)'],
    23 ],
    24 },
    25 { 'attr' => 'abstr', 'type' => 'wysiwyg', 'rusname' => 'Краткое описание', 'rows' => 10 },
    26 { 'attr' => 'icon', 'type' => 'image', 'rusname' => 'Аватар', preview => ['300x300','250x250','200x200','150x150','120x120','100x100','32x32'] },
    27 )
    28 }
    29
    30 sub class_name
    31 {
    32 return 'Блог';
    33 }
    34
    35 sub class_description
    36 {
    37 return 'Профиль блога';
    38 }
    39
    40 sub class_table
    41 {
    42 return 'blogs::SQL::BlogsTable';
    43 }
    44
    45 sub can_read {
    46 my $self = shift;
    47 my $uid = shift;
    48 return undef unless $uid;
    49
    50 if ( $uid == $self->uid || $self->status == 1 || ($self->status == 2 && $self->is_member($uid)) ) {
    51 return 1;
    52 } else {
    53 return 0;
    54 }
    55 }
    56
    57 sub why_cant_i_read {
    58 my $self = shift;
    59 my $uid = shift;
    60 return 'не указан пользователь' unless $uid;
    61
    62 if ( $self->status == 0 ) {
    63 return 'блог заблокирован';
    64 } elsif ( $self->status == 2 && !$self->is_member($uid) ) {
    65 return 'блог открыт только для участников сообщества';
    66 } else {
    67 return 'окстись, ты можешь прекрасно все читать...';
    68 }
    69 }
    70
    71 sub can_write {
    72 my $self = shift;
    73 my $uid = shift;
    74 return undef unless $uid;
    75
    76 return 1 if $uid == $self->uid;
    77 return 0 unless $self->status;
    78 if ( $self->type == 2 || ($self->type == 1 && $self->is_member($uid)) || ($self->type == 3 && ref $user) ) {
    79 return 1;
    80 } else {
    81 return 0;
    82 }
    83 }
    84
    85 sub why_cant_i_write {
    86 my $self = shift;
    87 my $uid = shift;
    88 return 'не указан пользователь' unless $uid;
    89
    90 if ( $self->status == 0 ) {
    91 return 'блог заблокирован';
    92 } elsif ( $self->type == 0 && $self->uid != $uid ) {
    93 return 'это чужой личный блог';
    94 } elsif ( $self->type == 1 && !$self->is_member($uid) ) {
    95 return 'вы не являетесь участником данного сообщества';
    96 } else {
    97 return 'окстись, ты можешь прекрасно все читать...';
    98 }
    99 }
    100
    101 sub is_member {
    102 my $self = shift;
    103 my $uid = shift;
    104 return undef unless $uid;
    105
    106 return (($uid == $self->uid) || (grep { $_ == $uid } $self->members)) ? 1 : 0;
    107 }
    108
    109 sub is_moderator {
    110 my $self = shift;
    111 my $uid = shift;
    112 return undef unless $uid;
    113
    114 return $uid == $self->uid || grep { $_ == $uid } $self->moderators ? 1 : 0;
    115 }
    116
    117 sub is_subscriber {
    118 my $self = shift;
    119 my $uid = shift;
    120 return undef unless $uid;
    121
    122 return (($uid == $self->uid) || (grep { $_ == $uid } $self->members, $self->readers)) ? 1 : 0;
    123 }
    124
    125 sub subscribe {
    126 my $self = shift;
    127 my $uid = shift;
    128 return undef unless $uid;
    129 return undef unless $self->id;
    130 return undef if $self->is_subscriber($uid);
    131
    132 my $link = blogs::SubscriberLink->new ( $keeper );
    133 $link->status( 1 );
    134 $link->source_id( $uid );
    135 $link->dest_id( $self->id );
    136 $link->dest_class( $self->class );
    137 $link->store;
    138 return undef unless $link->id;
    139
    140 push @{ $self->{readers} }, $uid;
    141 $self->store;
    142 return 1;
    143 }
    144
    145 sub unsubscribe {
    146 my $self = shift;
    147 my $uid = shift;
    148 return undef unless $uid;
    149 return undef unless $self->id;
    150
    151 warn "DELETE FROM ".blogs::SubscriberLink->class_table->db_table." WHERE source_id = ? AND dest_id = ? AND dest_class = ?\n" if $DEBUG;
    152 my $res = $keeper->SQL->prepare('DELETE FROM '.blogs::SubscriberLink->class_table->db_table.' WHERE source_id = ? AND dest_id = ? AND dest_class = ?');
    153 $res->execute( $uid, $self->id, $self->class );
    154 $res->finish;
    155
    156 @{ $self->{readers} } = grep { $_ != $uid } @{ $self->{readers} };
    157 $self->store;
    158 return 1;
    159 }
    160
    161 sub contenido_status_style
    162 {
    163 my $self = shift;
    164 if ( $self->status == 2 ) {
    165 return 'color:green;';
    166 } elsif ( $self->status == 3 ) {
    167 return 'color:olive;';
    168 } elsif ( $self->status == 4 ) {
    169 return 'color:green;';
    170 } elsif ( $self->status == 5 ) {
    171 return 'color:red;';
    172 }
    173 }
    174
    175 sub search_fields
    176 {
    177 return ('name');
    178 }
    179
    180 sub table_links
    181 {
    182 return [
    183 { name => 'Записи', class => 'blogs::Record', filter => 'blog_id', field => 'blog_id' },
    184 ];
    185 }
    186
    187 sub pre_store
    188 {
    189 my $self = shift;
    190
    191 unless ( $self->id ) {
    192 if ( $self->status == 3 && ref $user ) {
    193 $self->uid( $user->id );
    194 }
    195 }
    196
    197 my $default_section = $project->s_alias->{blogs} if ref $project->s_alias eq 'HASH' && exists $project->s_alias->{blogs};
    198 if ( $default_section ) {
    199 my $sections = $self->{sections};
    200 if ( ref $sections eq 'ARRAY' && scalar @$sections ) {
    201 my @new_sects = grep { $_ != $default_section } @$sections;
    202 push @new_sects, $default_section;
    203 $self->sections(@new_sects);
    204 } elsif ( $sections && !ref $sections && $sections != $default_section ) {
    205 my @new_sects = ($default_section, $sections);
    206 $self->sections(@new_sects);
    207 } else {
    208 $self->sections($default_section);
    209 }
    210 }
    211
    212 return 1;
    213 }
    214
    215 1;
  • utf8/plugins/blogs/lib/blogs/BlogSection.pm

     
    1 package blogs::BlogSection;
    2
    3 use base 'Contenido::Section';
    4
    5 sub extra_properties
    6 {
    7 return (
    8 { 'attr' => 'filters', 'hidden' => 1 },
    9 { 'attr' => 'default_document_class', 'default' => 'blogs::Blog' },
    10 # { 'attr' => 'brief', 'type' => 'text', 'rusname' => 'Описание секции' },
    11 )
    12 }
    13
    14 sub class_name
    15 {
    16 return 'Секция блогов';
    17 }
    18
    19 sub class_description
    20 {
    21 return 'Секция блогов';
    22 }
    23
    24 1;
  • utf8/plugins/blogs/lib/blogs/Comment.pm

     
    1 package blogs::Comment;
    2
    3 use base "Contenido::Document";
    4 use Digest::MD5;
    5 use Contenido::Globals;
    6
    7 sub extra_properties
    8 {
    9 return (
    10 { 'attr' => 'name', 'type' => 'string', 'rusname' => 'Сабж', },
    11 { 'attr' => 'status', 'type' => 'status', 'rusname' => 'Статус записи',
    12 'cases' => [
    13 [0, 'Запись неактивна'],
    14 [1, 'Запись активна'],
    15 # [2, 'Запись активна и видна только участникам'],
    16 # [3, 'Запись заблокирована'],
    17 ],
    18 },
    19 { 'attr' => 'in_reply', 'type' => 'text', 'rusname' => 'Выдержка из сообщения', 'rows' => 10 },
    20 { 'attr' => 'in_reply_id', 'type' => 'integer', 'rusname' => 'ID родительского сообщения' },
    21 { 'attr' => 'in_reply_uid', 'type' => 'integer', 'rusname' => 'ID пользователя родительского сообщения', 'rows' => 10 },
    22 { 'attr' => 'in_reply_author', 'type' => 'string', 'rusname' => 'Имя пользователя родительского сообщения', 'rows' => 10 },
    23 { 'attr' => 'body', 'type' => 'text', 'rusname' => 'Текст комментария', 'rows' => 20 },
    24 { 'attr' => 'author', 'type' => 'string', 'rusname' => 'Имя автора сообщения', },
    25 { 'attr' => 'pictures', 'type' => 'images', 'rusname' => 'Список картинок', preview => ['300x300','250x250','200x200','150x150','120x120','100x100'] },
    26 )
    27 }
    28
    29 sub class_name
    30 {
    31 return 'Комментарий к блогу';
    32 }
    33
    34 sub class_description
    35 {
    36 return 'Комментарий к блогу';
    37 }
    38
    39
    40 sub class_table
    41 {
    42 return 'blogs::SQL::CommentsTable';
    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:olive;';
    52 } elsif ( $self->status == 4 ) {
    53 return 'color:green;';
    54 } elsif ( $self->status == 5 ) {
    55 return 'color:red;';
    56 }
    57 }
    58
    59 #sub search_fields
    60 #{
    61 # return ('name');
    62 #}
    63
    64 #sub table_links
    65 #{
    66 # return [
    67 # { name => 'Записи', class => 'blogs::Record', filter => 'blog_id', field => 'blog_id' },
    68 # ];
    69 #}
    70
    71 sub pre_store
    72 {
    73 my $self = shift;
    74
    75 my $default_section = $project->s_alias->{blog_comments} if ref $project->s_alias eq 'HASH' && exists $project->s_alias->{blog_comments};
    76 if ( $default_section ) {
    77 my $sections = $self->{sections};
    78 if ( ref $sections eq 'ARRAY' && scalar @$sections ) {
    79 my @new_sects = grep { $_ != $default_section } @$sections;
    80 push @new_sects, $default_section;
    81 $self->sections(@new_sects);
    82 } elsif ( $sections && !ref $sections && $sections != $default_section ) {
    83 my @new_sects = ($default_section, $sections);
    84 $self->sections(@new_sects);
    85 } else {
    86 $self->sections($default_section);
    87 }
    88 }
    89
    90 return 1;
    91 }
    92
    93 1;
  • utf8/plugins/blogs/lib/blogs/Init.pm

     
    1 package blogs::Init;
    2
    3 use strict;
    4 use warnings 'all';
    5
    6 use Contenido::Globals;
    7 use blogs::Apache;
    8 use blogs::Keeper;
    9
    10
    11 # загрузка всех необходимых плагину классов
    12 # blogs::SQL::SomeTable
    13 # blogs::SomeClass
    14 Contenido::Init::load_classes(qw(
    15 blogs::SQL::BlogsTable
    16 blogs::SQL::RecordsTable
    17 blogs::SQL::MembersTable
    18 blogs::SQL::CommentsTable
    19 blogs::SQL::TagsTable
    20 blogs::SQL::TagCloudTable
    21
    22 blogs::TagCloud
    23
    24 blogs::Blog
    25 blogs::Record
    26 blogs::Comment
    27 blogs::MemberLink
    28 blogs::Tag
    29 blogs::SubscriberLink
    30
    31 blogs::RecordSection
    32 blogs::TagSection
    33 blogs::BlogSection
    34 ));
    35
    36 sub init {
    37 push @{ $state->{'available_documents'} }, qw( blogs::Blog blogs::Record blogs::Comment blogs::Tag );
    38 push @{ $state->{'available_sections'} }, qw( blogs::RecordSection blogs::TagSection blogs::BlogSection );
    39 push @{ $state->{'available_links'} }, qw( blogs::MemberLink blogs::TagCloud );
    40 0;
    41 }
    42
    43 1;
  • utf8/plugins/blogs/lib/blogs/Keeper.pm

     
    1 package blogs::Keeper;
    2
    3 use strict;
    4 use warnings 'all';
    5 use base qw(Contenido::Keeper);
    6
    7
    8 use Contenido::Globals;
    9
    10
    11 sub get_blogs {
    12 my $self = shift;
    13 my (%opts) = @_;
    14 my $uid = delete $opts{uid} || 0;
    15 my $owner = delete $opts{owner} || 0;
    16 my $type = delete $opts{type};
    17 my $id = delete $opts{id};
    18
    19 my $blog;
    20 my %getopts;
    21 if ( $uid ) {
    22 $getopts{status} = 'positive';
    23 } else {
    24 $getopts{status} = [1,2,3];
    25 }
    26 $getopts{uid} = $owner if $owner;
    27 $getopts{type} = defined $type ? $type : 'positive';
    28 if ( $id ) {
    29 $blog = $keeper->get_document_by_id ( $id, class => 'blogs::Blog', %getopts );
    30 if ( ref $blog ) {
    31 if ( $blog->type == 1 && $uid && $blog->uid != $uid ) {
    32 return undef unless grep { $_ == $uid } $blog->members;
    33 }
    34 }
    35 } else {
    36 if ( $uid ) {
    37 $getopts{lclass} = 'blogs::MemberLink',
    38 $getopts{lsource} = $uid;
    39 }
    40 $blog = $keeper->get_documents (
    41 class => 'blogs::Blog',
    42 %getopts,
    43 %opts,
    44 return_mode => 'array_ref',
    45 );
    46 if ( $owner && defined $type && $type == 0 ) {
    47 $blog = $blog->[0];
    48 }
    49 }
    50 return $blog;
    51 }
    52
    53 sub add_member {
    54 my $self = shift;
    55 my (%opts) = @_;
    56 my $id = delete $opts{blog} || 0;
    57 my $uid = delete $opts{uid} || [];
    58 my $moderator = delete $opts{moderator} || 0;
    59 return undef if !$uid || (ref $uid eq 'ARRAY' && !@$uid);
    60 return undef unless $id;
    61
    62 $uid = [$uid] unless ref $uid;
    63 my $blog = $keeper->get_document_by_id ( $id, class => 'blogs::Blog' );
    64 my @members = grep { my $mem = $_; !grep { $_ == $mem } @$uid } $blog->members;
    65 push @members, @$uid;
    66 $blog->members( @members ? @members : undef );
    67 if ( $moderator ) {
    68 my @moderators = grep { my $mem = $_; !grep { $_ == $mem } @$uid } $blog->moderators;
    69 push @moderators, @$uid;
    70 $blog->moderators( @moderators ? @moderators : undef );
    71 }
    72 $blog->store;
    73
    74 my @links = $keeper->get_links ( class => 'blogs::MemberLink', dest_id => $blog->id );
    75 foreach my $user_id ( @$uid ) {
    76 my ($link) = grep { $_->source_id == $user_id } @links;
    77 if ( ref $link && $moderator ) {
    78 $link->moderator( 1 );
    79 $link->store;
    80 } elsif ( ref $link ) {
    81 $link->moderator( 0 );
    82 $link->store;
    83 } else {
    84 $link = blogs::MemberLink->new( $keeper );
    85 $link->source_id( $user_id );
    86 $link->dest_id ( $blog->id );
    87 $link->dest_class ( $blog->class );
    88 $link->status( 1 );
    89 $link->moderator( $moderator );
    90 $link->store;
    91 }
    92 }
    93 1;
    94 }
    95
    96 sub remove_member {
    97 my $self = shift;
    98 my (%opts) = @_;
    99 my $id = delete $opts{blog} || 0;
    100 my $uid = delete $opts{uid} || 0;
    101 return undef unless $uid;
    102 return undef unless $id;
    103
    104 my $blog = $keeper->get_document_by_id ( $id, class => 'blogs::Blog' );
    105 my @members = grep { $_ != $uid } $blog->members;
    106 $blog->members( @members ? @members : undef );
    107 my @moderators = grep { $_!= $uid } $blog->moderators;
    108 $blog->moderators( @moderators ? @moderators : undef );
    109 $blog->store;
    110
    111 my @links = $keeper->get_links ( class => 'blogs::MemberLink', dest_id => $blog->id );
    112 my ($link) = grep { $_->source_id == $uid } @links;
    113 if ( ref $link ) {
    114 $link->delete;
    115 }
    116 1;
    117 }
    118
    119
    120 sub delete_blog {
    121 my $self = shift;
    122 my $id = shift;
    123 my (%opts) = @_;
    124
    125 if ( $opts{soft} ) {
    126 my $blog = $keeper->get_document_by_id ( $id, class => 'blogs::Blog' );
    127 $blog->status(0);
    128 $blog->store;
    129 } else {
    130 my $comments_db_table = blogs::SQL::CommentsTable->db_table;
    131 my $sthcom = $keeper->SQL->prepare( "delete from $comments_db_table where blog_id = ?" );
    132 $sthcom->execute( $id );
    133 $sthcom->finish;
    134 my $records = $keeper->get_documents (
    135 blog_id => $id,
    136 class => 'blogs::Record',
    137 no_limit => 1,
    138 return_mode => 'array_ref',
    139 );
    140 foreach my $rec ( @$records ) {
    141 $rec->delete( attachments => 1 );
    142 }
    143 my $blog = $keeper->get_document_by_id ( $id, class => 'blogs::Blog' );
    144 $blog->delete( attachments => 1 );
    145 }
    146 }
    147
    148
    149 sub delete_record {
    150 my $self = shift;
    151 my $id = shift;
    152 my (%opts) = @_;
    153
    154 my $comments_db_table = blogs::SQL::CommentsTable->db_table;
    155 my $sthcom = $keeper->SQL->prepare( "delete from $comments_db_table where record_id = ?" );
    156 $sthcom->execute( $id );
    157 $sthcom->finish;
    158 my $record = $keeper->get_document_by_id ( $id, class => 'blogs::Record' );
    159 $record->delete( attachments => 1 );
    160 }
    161
    162 sub add_comment {
    163 my $self = shift;
    164 my (%opts) = @_;
    165 }
    166
    167
    168 sub get_comments {
    169 my $self = shift;
    170 my (%opts) = @_;
    171 my $record_id = delete $opts{record_id};
    172
    173 return undef unless $record_id;
    174 my $comment_tree = {};
    175 my $comments = $keeper->get_documents (
    176 class => 'blogs::Comment',
    177 record_id => $record_id,
    178 return_mode => 'array_ref',
    179 ) || [];
    180 foreach my $comment ( @$comments ) {
    181 $comment_tree->{$comment->pid} = [] unless exists $comment_tree->{$comment->pid};
    182 push @{ $comment_tree->{$comment->pid} }, $comment;
    183 }
    184 return ( $comment_tree, $comments );
    185 }
    186
    187 1;
  • utf8/plugins/blogs/lib/blogs/MemberLink.pm

     
    1 package blogs::MemberLink;
    2
    3 use strict;
    4 use vars qw(@ISA);
    5
    6 use Contenido::Link;
    7 @ISA = ('Contenido::Link');
    8
    9 sub extra_properties
    10 {
    11 return (
    12 );
    13 }
    14
    15 sub class_name
    16 {
    17 return 'Участник блога';
    18 }
    19
    20 sub class_description
    21 {
    22 return 'Связь между пользователями и блогами';
    23 }
    24
    25 #sub available_sources
    26 #{
    27 # return [ qw(formula1::Championship) ];
    28 #}
    29
    30 sub available_destinations
    31 {
    32 return [ qw(blogs::Blog) ];
    33 }
    34
    35 sub class_table
    36 {
    37 return 'blogs::SQL::MembersTable';
    38 }
    39
    40 1;
  • utf8/plugins/blogs/lib/blogs/Record.pm

     
    1 package blogs::Record;
    2
    3 use base "Contenido::Document";
    4 use Encode;
    5 use Contenido::Globals;
    6
    7 sub extra_properties
    8 {
    9 return (
    10 { 'attr' => 'name', 'type' => 'string', 'rusname' => 'Сабж / настроение' },
    11 { 'attr' => 'status', 'type' => 'status', 'rusname' => 'Статус записи',
    12 'cases' => [
    13 [0, 'Запись неактивна'],
    14 [1, 'Запись активна'],
    15 [2, 'Запись вынесена в топ блога'],
    16 [3, 'Запись вынесена на главную страницу'],
    17 ],
    18 },
    19 { 'attr' => 'abstr', 'type' => 'wysiwyg', 'rusname' => 'Начало записи', 'rows' => 10 },
    20 { 'attr' => 'body', 'type' => 'wysiwyg', 'rusname' => 'Текст под катом', 'rows' => 30 },
    21 { 'attr' => 'author', 'type' => 'string', 'rusname' => 'Имя автора сообщения', },
    22 { 'attr' => 'video', 'type' => 'text', 'rusname' => 'Поле для вставки HTML-кода видео', 'rows' => 10 },
    23 { 'attr' => 'pictures', 'type' => 'images', 'rusname' => 'Список картинок', preview => ['300x300','250x250','200x200','150x150','120x120','100x100'] },
    24 )
    25 }
    26
    27 sub class_name
    28 {
    29 return 'Запись блога';
    30 }
    31
    32 sub class_description
    33 {
    34 return 'Запись блога';
    35 }
    36
    37
    38 sub class_table
    39 {
    40 return 'blogs::SQL::RecordsTable';
    41 }
    42
    43 sub contenido_status_style
    44 {
    45 my $self = shift;
    46 if ( $self->status == 2 ) {
    47 return 'color:green;';
    48 } elsif ( $self->status == 3 ) {
    49 return 'color:olive;';
    50 } elsif ( $self->status == 4 ) {
    51 return 'color:green;';
    52 } elsif ( $self->status == 5 ) {
    53 return 'color:red;';
    54 }
    55 }
    56
    57 sub search_fields
    58 {
    59 return ('tags', 'name');
    60 }
    61
    62 sub table_links
    63 {
    64 return [
    65 { name => 'Комменты', class => 'blogs::Comment', filter => 'record_id', field => 'record_id' },
    66 ];
    67 }
    68
    69 sub pre_store
    70 {
    71 my $self = shift;
    72
    73 if ( !$self->id && !$self->uid ) {
    74 if ( ref $session && exists $session->{id} && $session->{id} ) {
    75 $self->uid( $session->{id} );
    76 } elsif ( ref $user ) {
    77 $self->uid( $user->id );
    78 }
    79 }
    80
    81 my $default_section = $project->s_alias->{blog_records} if ref $project->s_alias eq 'HASH' && exists $project->s_alias->{blog_records};
    82 if ( $default_section ) {
    83 my $sections = $self->{sections};
    84 if ( ref $sections eq 'ARRAY' && scalar @$sections ) {
    85 my @new_sects = grep { $_ != $default_section } @$sections;
    86 push @new_sects, $default_section;
    87 $self->sections(@new_sects);
    88 } elsif ( $sections && !ref $sections && $sections != $default_section ) {
    89 my @new_sects = ($default_section, $sections);
    90 $self->sections(@new_sects);
    91 } else {
    92 $self->sections($default_section);
    93 }
    94 }
    95
    96 return 1;
    97 }
    98
    99
    100 sub post_store
    101 {
    102 my $self = shift;
    103
    104 my @links = $self->keeper->get_links(
    105 class => 'blogs::TagCloud',
    106 dest_id => $self->id,
    107 );
    108 foreach my $link ( @links ) {
    109 $link->delete();
    110 }
    111 if ( $self->tags ) {
    112 my @tags = map { encode('utf-8', lc($_)) } split /[\t\ ]*,[\t\ ]*/, decode("utf-8", $self->tags);
    113 foreach my $tag ( @tags ) {
    114 my ($tid) = $self->keeper->get_documents(
    115 name => $tag,
    116 ilike => 1,
    117 class => 'blogs::Tag',
    118 ids => 1,
    119 limit => 1,
    120 );
    121 unless ( $tid ) {
    122 my $tobj = blogs::Tag->new( $self->keeper );
    123 $tobj->name( $tag );
    124 $tobj->status( 1 );
    125 $tobj->store;
    126 $tid = $tobj->id;
    127 }
    128 my $link = blogs::TagCloud->new( $keeper );
    129 $link->status( 1 );
    130 $link->source_id( $tid );
    131 $link->source_class( 'blogs::Tag' );
    132 $link->dest_id( $self->id );
    133 $link->dest_class( $self->class );
    134 $link->store;
    135 }
    136 }
    137
    138 1;
    139 }
    140
    141
    142 sub pre_delete
    143 {
    144 my $self = shift;
    145
    146 my $comments_db_table = blogs::SQL::CommentsTable->db_table;
    147 my $sthcom = $self->keeper->SQL->prepare( "delete from $comments_db_table where record_id = ?" );
    148 $sthcom->execute( $self->id );
    149 $sthcom->finish;
    150
    151 my $tags_db_table = blogs::SQL::TagsTable->db_table;
    152 my $sthtag = $self->keeper->SQL->prepare( "delete from $comments_db_table where dest_id = ? and dest_class = ?" );
    153 $sthtag->execute( $self->id, $self->class );
    154 $sthtag->finish;
    155
    156 1;
    157 }
    158
    159 1;
  • utf8/plugins/blogs/lib/blogs/RecordSection.pm

     
    1 package blogs::RecordSection;
    2
    3 use base 'Contenido::Section';
    4
    5 sub extra_properties
    6 {
    7 return (
    8 { 'attr' => 'filters', 'hidden' => 1 },
    9 { 'attr' => 'default_document_class', 'default' => 'blogs::Record' },
    10 # { 'attr' => 'brief', 'type' => 'text', 'rusname' => 'Описание секции' },
    11 )
    12 }
    13
    14 sub class_name
    15 {
    16 return 'Секция записей в блогах';
    17 }
    18
    19 sub class_description
    20 {
    21 return 'Секция записей в блогах';
    22 }
    23
    24 1;
  • utf8/plugins/blogs/lib/blogs/SQL/BlogsTable.pm

     
    1 package blogs::SQL::BlogsTable;
    2
    3 use strict;
    4 use base 'SQL::DocumentTable';
    5
    6 sub db_table
    7 {
    8 return 'blogs';
    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 _type_filter
    30 );
    31 return \@available_filters;
    32 }
    33
    34 # ----------------------------------------------------------------------------
    35 # Свойства храним в массивах, потому что порядок важен!
    36 # Это общие свойства - одинаковые для всех документов.
    37 #
    38 # attr - обязательный параметр, название атрибута;
    39 # type - тип аттрибута, требуется для отображдения;
    40 # rusname - русское название, опять же требуется для отображения;
    41 # hidden - равен 1, когда
    42 # readonly - инициализации при записи только без изменения в дальнейшем
    43 # db_field - поле в таблице
    44 # default - значение по умолчанию (поле всегда имеет это значение)
    45 # ----------------------------------------------------------------------------
    46 sub required_properties
    47 {
    48 my $self = shift;
    49
    50 my @parent_properties = $self->SUPER::required_properties;
    51 return (
    52 @parent_properties,
    53 { # Тип блога...
    54 'attr' => 'type',
    55 'type' => 'status',
    56 'cases' => [
    57 [0, 'Личный блог'],
    58 [1, 'Групповой блог'],
    59 ],
    60 'rusname' => 'Пользователь',
    61 'db_field' => 'type',
    62 'db_type' => 'integer',
    63 'db_opts' => 'default 0',
    64 },
    65 { # Пользователь...
    66 'attr' => 'uid',
    67 'type' => 'integer',
    68 'rusname' => 'Пользователь',
    69 'db_field' => 'uid',
    70 'db_type' => 'integer',
    71 'db_opts' => 'not null',
    72 },
    73 { # Количество записей...
    74 'attr' => 'records',
    75 'type' => 'checkbox',
    76 'rusname' => 'Количество записей в блоге',
    77 'hidden' => 1,
    78 'db_field' => 'records',
    79 'db_type' => 'integer',
    80 'db_opts' => 'not null',
    81 },
    82 { # Участники...
    83 'attr' => 'members',
    84 'type' => 'text',
    85 'rusname' => 'Участники',
    86 'hidden' => 1,
    87 'db_field' => 'members',
    88 'db_type' => 'integer[]',
    89 },
    90 { # Читатели...
    91 'attr' => 'readers',
    92 'type' => 'text',
    93 'rusname' => 'Читатели',
    94 'hidden' => 1,
    95 'db_field' => 'readers',
    96 'db_type' => 'integer[]',
    97 },
    98 { # Модераторы...
    99 'attr' => 'moderators',
    100 'type' => 'checkbox',
    101 'rusname' => 'Модераторы',
    102 'hidden' => 1,
    103 'db_field' => 'moderators',
    104 'db_type' => 'integer[]',
    105 },
    106 );
    107 }
    108
    109 sub _uid_filter {
    110 my ($self,%opts)=@_;
    111 return undef unless ( exists $opts{uid} && $opts{uid} );
    112 return &SQL::Common::_generic_int_filter('d.uid', $opts{uid});
    113 }
    114
    115 sub _type_filter {
    116 my ($self,%opts)=@_;
    117 return undef unless ( exists $opts{type} );
    118 return &SQL::Common::_generic_int_filter('d.type', $opts{type});
    119 }
    120
    121
    122 sub _link_filter {
    123 my ($self,%opts)=@_;
    124
    125 my @wheres=();
    126 my @binds=();
    127
    128 # Связь определенного класса
    129 if (exists($opts{lclass})) {
    130 my ($where, $values) = SQL::Common::_generic_text_filter('l.class', $opts{lclass});
    131 push (@wheres, $where);
    132 push @binds, (ref $values ? @$values : $values) if defined $values;
    133 }
    134
    135 my $lclass = $opts{lclass} || 'Contenido::Link';
    136 my $link_table = $lclass->_get_table->db_table();
    137
    138 # Ограничение по статусу связи
    139 if ( exists $opts{lstatus} ) {
    140 my ($where, $values) = SQL::Common::_generic_int_filter('l.status', $opts{lstatus});
    141 push (@wheres, $where);
    142 push (@binds, ref($values) ? @$values:$values) if (defined $values);
    143 }
    144
    145 # Связь с определенным документ(ом/тами) по цели линка
    146 if ( exists $opts{ldest} ) {
    147 my ($where, $values) = SQL::Common::_generic_int_filter('l.dest_id', $opts{ldest});
    148 push (@wheres, $where);
    149 push (@binds, ref($values) ? @$values:$values) if (defined $values);
    150 if ( $self->_single_class || $opts{lclass} eq 'blogs::MemberLink' ) {
    151 return (\@wheres, \@binds, " join $link_table as l on l.source_id=d.id");
    152 } else {
    153 return (\@wheres, \@binds, " join $link_table as l on l.source_id=d.id and l.source_class=d.class");
    154 }
    155 }
    156
    157 # Связь с определенным документ(ом/тами) по источнику линка
    158 if ( exists $opts{lsource} ) {
    159 my ($where, $values) = SQL::Common::_generic_int_filter('l.source_id', $opts{lsource});
    160 push (@wheres, $where);
    161 push (@binds, ref($values) ? @$values:$values) if (defined $values);
    162 if ( $self->_single_class || $opts{lclass} eq 'blogs::MemberLink' ) {
    163 return (\@wheres, \@binds, " join $link_table as l on l.dest_id=d.id");
    164 } else {
    165 return (\@wheres, \@binds, " join $link_table as l on l.dest_id=d.id and l.dest_class=d.class");
    166 }
    167 }
    168
    169 return (undef);
    170 }
    171
    172
    173 1;
    174
  • utf8/plugins/blogs/lib/blogs/SQL/CommentsTable.pm

     
    1 package blogs::SQL::CommentsTable;
    2
    3 use strict;
    4 use base 'SQL::DocumentTable';
    5
    6 sub db_table
    7 {
    8 return 'blog_comments';
    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 _pid_filter
    30 _blog_id_filter
    31 _record_id_filter
    32 );
    33 return \@available_filters;
    34 }
    35
    36 # ----------------------------------------------------------------------------
    37 # Свойства храним в массивах, потому что порядок важен!
    38 # Это общие свойства - одинаковые для всех документов.
    39 #
    40 # attr - обязательный параметр, название атрибута;
    41 # type - тип аттрибута, требуется для отображдения;
    42 # rusname - русское название, опять же требуется для отображения;
    43 # hidden - равен 1, когда
    44 # readonly - инициализации при записи только без изменения в дальнейшем
    45 # db_field - поле в таблице
    46 # default - значение по умолчанию (поле всегда имеет это значение)
    47 # ----------------------------------------------------------------------------
    48 sub required_properties
    49 {
    50 my $self = shift;
    51
    52 my @parent_properties = $self->SUPER::required_properties;
    53 return (
    54 @parent_properties,
    55 { # Пользователь...
    56 'attr' => 'uid',
    57 'type' => 'integer',
    58 'rusname' => 'Пользователь',
    59 'db_field' => 'uid',
    60 'db_type' => 'integer',
    61 'db_opts' => 'not null',
    62 },
    63 { # Блог...
    64 'attr' => 'blog_id',
    65 'type' => 'integer',
    66 'rusname' => 'Блог',
    67 'db_field' => 'blog_id',
    68 'db_type' => 'integer',
    69 'db_opts' => 'not null',
    70 },
    71 { # Запись блога...
    72 'attr' => 'record_id',
    73 'type' => 'integer',
    74 'rusname' => 'Запись блога',
    75 'db_field' => 'record_id',
    76 'db_type' => 'integer',
    77 'db_opts' => 'not null',
    78 },
    79 { # Родитель...
    80 'attr' => 'pid',
    81 'type' => 'integer',
    82 'rusname' => 'Родитель',
    83 'db_field' => 'pid',
    84 'db_type' => 'integer',
    85 'db_opts' => 'not null',
    86 },
    87 );
    88 }
    89
    90 sub _uid_filter {
    91 my ($self,%opts)=@_;
    92 return undef unless ( exists $opts{uid} && $opts{uid} );
    93 return &SQL::Common::_generic_int_filter('d.uid', $opts{uid});
    94 }
    95
    96 sub _blog_id_filter {
    97 my ($self,%opts)=@_;
    98 return undef unless ( exists $opts{blog_id} );
    99 return &SQL::Common::_generic_int_filter('d.blog_id', $opts{blog_id});
    100 }
    101
    102 sub _record_id_filter {
    103 my ($self,%opts)=@_;
    104 return undef unless ( exists $opts{record_id} );
    105 return &SQL::Common::_generic_int_filter('d.record_id', $opts{record_id});
    106 }
    107
    108 sub _pid_filter {
    109 my ($self,%opts)=@_;
    110 return undef unless ( exists $opts{pid} );
    111 return &SQL::Common::_generic_int_filter('d.pid', $opts{pid});
    112 }
    113
    114 sub _get_orders {
    115 my ($self, %opts) = @_;
    116
    117 if ($opts{order_by}) {
    118 return ' order by '.$opts{order_by};
    119 } else {
    120 return ' order by ctime';
    121 }
    122 return undef;
    123 }
    124
    125 1;
    126
  • utf8/plugins/blogs/lib/blogs/SQL/MembersTable.pm

     
    1 package blogs::SQL::MembersTable;
    2
    3 use strict;
    4 use Contenido::Globals;
    5 use base 'SQL::LinkTable';
    6
    7 sub db_table
    8 {
    9 return 'blog_members';
    10 }
    11
    12 sub available_filters {
    13 my @available_filters = qw(
    14 _class_filter
    15 _status_filter
    16 _in_id_filter
    17 _id_filter
    18 _name_filter
    19 _class_excludes_filter
    20 _excludes_filter
    21 _datetime_filter
    22 _date_equal_filter
    23 _date_filter
    24
    25 _dest_id_filter
    26 _dest_class_filter
    27 _source_id_filter
    28 _source_class_filter
    29 );
    30 return \@available_filters;
    31 }
    32
    33 # ----------------------------------------------------------------------------
    34 # Свойства храним в массивах, потому что порядок важен!
    35 # Это общие свойства - одинаковые для всех документов.
    36 #
    37 # attr - обязательный параметр, название атрибута;
    38 # type - тип аттрибута, требуется для отображдения;
    39 # rusname - русское название, опять же требуется для отображения;
    40 # hidden - равен 1, когда
    41 # readonly - инициализации при записи только без изменения в дальнейшем
    42 # db_field - поле в таблице
    43 # default - значение по умолчанию (поле всегда имеет это значение)
    44 # ----------------------------------------------------------------------------
    45 sub required_properties
    46 {
    47 my $self = shift;
    48
    49 my @parent_properties = grep { $_->{attr} ne 'source_class' } $self->SUPER::required_properties;
    50 return (
    51 @parent_properties,
    52 { # Is Moder
    53 'attr' => 'moderator',
    54 'type' => 'integer',
    55 'rusname' => 'Является модератором',
    56 'db_field' => 'moderator',
    57 'db_type' => 'smallint',
    58 'default' => 0,
    59 },
    60 );
    61 }
    62
    63 ########### FILTERS DESCRIPTION ####################################################################################
    64
    65
    66 1;
    67
  • utf8/plugins/blogs/lib/blogs/SQL/RecordsTable.pm

     
    1 package blogs::SQL::RecordsTable;
    2
    3 use strict;
    4 use base 'SQL::DocumentTable';
    5
    6 sub db_table
    7 {
    8 return 'blog_records';
    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 _blog_id_filter
    30 _tags_filter
    31 _public_records_filter
    32 );
    33 return \@available_filters;
    34 }
    35
    36 # ----------------------------------------------------------------------------
    37 # Свойства храним в массивах, потому что порядок важен!
    38 # Это общие свойства - одинаковые для всех документов.
    39 #
    40 # attr - обязательный параметр, название атрибута;
    41 # type - тип аттрибута, требуется для отображдения;
    42 # rusname - русское название, опять же требуется для отображения;
    43 # hidden - равен 1, когда
    44 # readonly - инициализации при записи только без изменения в дальнейшем
    45 # db_field - поле в таблице
    46 # default - значение по умолчанию (поле всегда имеет это значение)
    47 # ----------------------------------------------------------------------------
    48 sub required_properties
    49 {
    50 my $self = shift;
    51
    52 my @parent_properties = $self->SUPER::required_properties;
    53 return (
    54 @parent_properties,
    55 { # Пользователь...
    56 'attr' => 'uid',
    57 'type' => 'integer',
    58 'rusname' => 'Пользователь',
    59 'db_field' => 'uid',
    60 'db_type' => 'integer',
    61 'db_opts' => 'not null',
    62 },
    63 { # Блог...
    64 'attr' => 'blog_id',
    65 'type' => 'integer',
    66 'rusname' => 'Блог',
    67 'db_field' => 'blog_id',
    68 'db_type' => 'integer',
    69 'db_opts' => 'not null',
    70 },
    71 { # Количество записей...
    72 'attr' => 'comments',
    73 'type' => 'integer',
    74 'rusname' => 'Количество комментариев',
    75 'db_field' => 'comments',
    76 'db_type' => 'integer',
    77 'db_opts' => 'default 0',
    78 },
    79 {
    80 'attr' => 'tags',
    81 'type' => 'string',
    82 'rusname' => 'Теги (через запятую)',
    83 'shortname' => 'Теги',
    84 'db_field' => 'tags',
    85 'db_type' => 'text',
    86 },
    87 );
    88 }
    89
    90 sub _uid_filter {
    91 my ($self,%opts)=@_;
    92 return undef unless ( exists $opts{uid} && $opts{uid} );
    93 return &SQL::Common::_generic_int_filter('d.uid', $opts{uid});
    94 }
    95
    96 sub _blog_id_filter {
    97 my ($self,%opts)=@_;
    98 return undef unless ( exists $opts{blog_id} );
    99 return &SQL::Common::_generic_int_filter('d.blog_id', $opts{blog_id});
    100 }
    101
    102 sub _tags_filter {
    103 my ($self,%opts)=@_;
    104 return undef unless ( exists $opts{tags} );
    105 my (@wheres, @binds, $join);
    106
    107 my $link_table = blogs::SQL::TagCloudTable->db_table;
    108 my $tag_table = blogs::SQL::TagsTable->db_table;
    109 $join = " join $link_table as l on l.dest_id=d.id and l.dest_class=d.class";
    110 push @wheres, "l.source_id in (select id from $tag_table where name ilike ?)";
    111 push @binds, $opts{tags};
    112 return (\@wheres, \@binds, $join);
    113 }
    114
    115 sub _public_records_filter {
    116 my ($self,%opts)=@_;
    117 return undef unless ( exists $opts{public} );
    118
    119 my ($where, $values, $joins) = ([], [], []);
    120 push @$joins, ' INNER JOIN blogs AS b ON d.blog_id=b.id ';
    121 push @$where, ' b.type = ? ';
    122 push @$values, $opts{public};
    123
    124 return ($where, $values, $joins);
    125 }
    126
    127 sub _get_orders {
    128 my ($self, %opts) = @_;
    129
    130 if ($opts{order_by}) {
    131 return ' order by '.$opts{order_by};
    132 } else {
    133 return ' order by dtime desc';
    134 }
    135 return undef;
    136 }
    137
    138 1;
    139
  • utf8/plugins/blogs/lib/blogs/SQL/TagCloudTable.pm

     
    1 package blogs::SQL::TagCloudTable;
    2
    3 use strict;
    4 use Contenido::Globals;
    5 use base 'SQL::LinkTable';
    6
    7 sub db_table
    8 {
    9 return 'blog_tag_cloud';
    10 }
    11
    12 sub available_filters {
    13 my @available_filters = qw(
    14 _class_filter
    15 _status_filter
    16 _in_id_filter
    17 _id_filter
    18 _class_excludes_filter
    19 _excludes_filter
    20 _datetime_filter
    21 _date_equal_filter
    22 _date_filter
    23
    24 _dest_id_filter
    25 _dest_class_filter
    26 _source_id_filter
    27 _source_class_filter
    28 );
    29 return \@available_filters;
    30 }
    31
    32 # ----------------------------------------------------------------------------
    33 # Свойства храним в массивах, потому что порядок важен!
    34 # Это общие свойства - одинаковые для всех документов.
    35 #
    36 # attr - обязательный параметр, название атрибута;
    37 # type - тип аттрибута, требуется для отображдения;
    38 # rusname - русское название, опять же требуется для отображения;
    39 # hidden - равен 1, когда
    40 # readonly - инициализации при записи только без изменения в дальнейшем
    41 # db_field - поле в таблице
    42 # default - значение по умолчанию (поле всегда имеет это значение)
    43 # ----------------------------------------------------------------------------
    44 sub required_properties
    45 {
    46 my $self = shift;
    47
    48 my @parent_properties = $self->SUPER::required_properties;
    49 return (
    50 @parent_properties,
    51 );
    52 }
    53
    54 ########### FILTERS DESCRIPTION ####################################################################################
    55
    56
    57 1;
  • utf8/plugins/blogs/lib/blogs/SQL/TagsTable.pm

     
    1 package blogs::SQL::TagsTable;
    2
    3 use strict;
    4 use base 'SQL::DocumentTable';
    5
    6 sub db_table
    7 {
    8 return 'blog_tags';
    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 _s_filter
    21
    22 _excludes_filter
    23 _link_filter
    24 _uid_filter
    25 );
    26 return \@available_filters;
    27 }
    28
    29 # ----------------------------------------------------------------------------
    30 # Свойства храним в массивах, потому что порядок важен!
    31 # Это общие свойства - одинаковые для всех документов.
    32 #
    33 # attr - обязательный параметр, название атрибута;
    34 # type - тип аттрибута, требуется для отображдения;
    35 # rusname - русское название, опять же требуется для отображения;
    36 # hidden - равен 1, когда
    37 # readonly - инициализации при записи только без изменения в дальнейшем
    38 # db_field - поле в таблице
    39 # default - значение по умолчанию (поле всегда имеет это значение)
    40 # ----------------------------------------------------------------------------
    41 sub required_properties
    42 {
    43 my $self = shift;
    44
    45 my @parent_properties = grep { $_->{attr} ne 'dtime' && $_->{attr} ne 'sections' } $self->SUPER::required_properties;
    46 return (
    47 @parent_properties,
    48 { # Пользователь...
    49 'attr' => 'uid',
    50 'type' => 'integer',
    51 'rusname' => 'Пользователь',
    52 'hidden' => 1,
    53 'db_field' => 'uid',
    54 'db_type' => 'integer',
    55 'db_opts' => 'not null',
    56 },
    57 { # Количество записей...
    58 'attr' => 'rate',
    59 'type' => 'checkbox',
    60 'rusname' => 'Количество упоминаний в блогах',
    61 'hidden' => 1,
    62 'default' => 0,
    63 'db_field' => 'rate',
    64 'db_type' => 'integer',
    65 'db_opts' => 'default 0',
    66 },
    67 { # Массив секций, обрабатывается специальным образом...
    68 'attr' => 'sections',
    69 'type' => 'sections_list',
    70 'rusname' => 'Секции',
    71 'hidden' => 1,
    72 'db_field' => 'sections',
    73 'db_type' => 'integer',
    74 },
    75 );
    76 }
    77
    78
    79 sub _uid_filter {
    80 my ($self,%opts)=@_;
    81 return undef unless ( exists $opts{uid} && $opts{uid} );
    82 return &SQL::Common::_generic_int_filter('d.uid', $opts{uid});
    83 }
    84
    85
    86 sub _s_filter {
    87 my ($self,%opts)=@_;
    88 return undef unless ( exists $opts{s} );
    89 return &SQL::Common::_generic_int_filter('d.sections', $opts{s});
    90 }
    91
    92
    93 sub _link_filter {
    94 my ($self,%opts)=@_;
    95
    96 my @wheres=();
    97 my @binds=();
    98
    99 # Связь определенного класса
    100 if (exists($opts{lclass})) {
    101 my ($where, $values) = SQL::Common::_generic_text_filter('l.class', $opts{lclass});
    102 push (@wheres, $where);
    103 push @binds, (ref $values ? @$values : $values) if defined $values;
    104 }
    105
    106 my $lclass = $opts{lclass} || 'Contenido::Link';
    107 my $link_table = $lclass->_get_table->db_table();
    108
    109 # Ограничение по статусу связи
    110 if ( exists $opts{lstatus} ) {
    111 my ($where, $values) = SQL::Common::_generic_int_filter('l.status', $opts{lstatus});
    112 push (@wheres, $where);
    113 push (@binds, ref($values) ? @$values:$values) if (defined $values);
    114 }
    115
    116 # Связь с определенным документ(ом/тами) по цели линка
    117 if ( exists $opts{ldest} ) {
    118 my ($where, $values) = SQL::Common::_generic_int_filter('l.dest_id', $opts{ldest});
    119 push (@wheres, $where);
    120 push (@binds, ref($values) ? @$values:$values) if (defined $values);
    121 if ( $self->_single_class || $opts{lclass} eq 'blogs::TagCloud' ) {
    122 return (\@wheres, \@binds, " join $link_table as l on l.source_id=d.id");
    123 } else {
    124 return (\@wheres, \@binds, " join $link_table as l on l.source_id=d.id and l.source_class=d.class");
    125 }
    126 }
    127
    128 # Связь с определенным документ(ом/тами) по источнику линка
    129 if ( exists $opts{lsource} ) {
    130 my ($where, $values) = SQL::Common::_generic_int_filter('l.source_id', $opts{lsource});
    131 push (@wheres, $where);
    132 push (@binds, ref($values) ? @$values:$values) if (defined $values);
    133 if ( $self->_single_class || $opts{lclass} eq 'blogs::TagCloud' ) {
    134 return (\@wheres, \@binds, " join $link_table as l on l.dest_id=d.id");
    135 } else {
    136 return (\@wheres, \@binds, " join $link_table as l on l.dest_id=d.id and l.dest_class=d.class");
    137 }
    138 }
    139
    140 return (undef);
    141 }
    142
    143
    144 1;
    145
  • utf8/plugins/blogs/lib/blogs/State.pm.proto

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

     
    1 package blogs::SubscriberLink;
    2
    3 use strict;
    4 use vars qw(@ISA);
    5
    6 use Contenido::Link;
    7 @ISA = ('Contenido::Link');
    8
    9 sub extra_properties
    10 {
    11 return (
    12 { 'attr' => 'moderator', 'hidden' => 1, },
    13 );
    14 }
    15
    16 sub class_name
    17 {
    18 return 'Подписчик блога';
    19 }
    20
    21 sub class_description
    22 {
    23 return 'Связь между пользователями и блогами';
    24 }
    25
    26 #sub available_sources
    27 #{
    28 # return [ qw(formula1::Championship) ];
    29 #}
    30
    31 sub available_destinations
    32 {
    33 return [ qw(blogs::Blog) ];
    34 }
    35
    36 sub class_table
    37 {
    38 return 'blogs::SQL::MembersTable';
    39 }
    40
    41 1;
  • utf8/plugins/blogs/lib/blogs/Tag.pm

     
    1 package blogs::Tag;
    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 ],
    15 },
    16 )
    17 }
    18
    19 sub class_name
    20 {
    21 return 'Тег для блогов';
    22 }
    23
    24 sub class_description
    25 {
    26 return 'Тег для блогов';
    27 }
    28
    29
    30 sub class_table
    31 {
    32 return 'blogs::SQL::TagsTable';
    33 }
    34
    35 #sub search_fields
    36 #{
    37 # return ('name');
    38 #}
    39
    40 sub pre_store
    41 {
    42 my $self = shift;
    43
    44 my $default_section = $project->s_alias->{blog_cloud} if ref $project->s_alias eq 'HASH' && exists $project->s_alias->{blog_cloud};
    45 $self->sections( $default_section ) unless $self->sections;
    46
    47 unless ( $self->id ) {
    48 if ( $user && ref $user ) {
    49 $self->uid( $user->id );
    50 } elsif ( $session && ref $session eq 'HASH' && exists $session->{id} ) {
    51 $self->uid( $session->{id} );
    52 }
    53 }
    54
    55 return 1;
    56 }
    57
    58 sub pre_delete
    59 {
    60 my $self = shift;
    61
    62 my $comments_db_table = blogs::SQL::TagCloudTable->db_table;
    63 my $sthcom = $self->keeper->SQL->prepare( "delete from $comments_db_table where source_id = ?" );
    64 $sthcom->execute( $self->id );
    65 $sthcom->finish;
    66
    67 1;
    68 }
    69
    70 1;
  • utf8/plugins/blogs/lib/blogs/TagCloud.pm

     
    1 package blogs::TagCloud;
    2
    3 use strict;
    4 use vars qw(@ISA);
    5
    6 use base 'Contenido::Link';
    7
    8 sub extra_properties
    9 {
    10 return (
    11 );
    12 }
    13
    14 sub class_name
    15 {
    16 return 'Элемент облака тегов';
    17 }
    18
    19 sub class_description
    20 {
    21 return 'Связь между тегом и записью в блоге';
    22 }
    23
    24 sub available_sources
    25 {
    26 return [ qw(blogs::Tag) ];
    27 }
    28
    29 sub available_destinations
    30 {
    31 return [ qw(blogs::Record) ];
    32 }
    33
    34 sub class_table
    35 {
    36 return 'blogs::SQL::TagCloudTable';
    37 }
    38
    39 1;
  • utf8/plugins/blogs/lib/blogs/TagSection.pm

     
    1 package blogs::TagSection;
    2
    3 use base 'Contenido::Section';
    4
    5 sub extra_properties
    6 {
    7 return (
    8 { 'attr' => 'filters', 'hidden' => 1 },
    9 { 'attr' => 'default_document_class', 'default' => 'blogs::Tag' },
    10 # { 'attr' => 'brief', 'type' => 'text', 'rusname' => 'Описание секции' },
    11 )
    12 }
    13
    14 sub class_name
    15 {
    16 return 'Секция тегов в блогах';
    17 }
    18
    19 sub class_description
    20 {
    21 return 'Секция тегов в блогах';
    22 }
    23
    24 1;
  • utf8/plugins/blogs/sql/TOAST/blog_members.sql

     
    1 create table blog_members
    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 btime timestamp not null default now(),
    8 etime timestamp not null default now(),
    9 status smallint not null default 1,
    10 source_id integer not null,
    11 moderator smallint default 0,
    12 temporary smallint default 0,
    13 dest_id integer not null,
    14 dest_class text not null default 'blogs::Blog',
    15 data text
    16 );
    17 create index blog_members_source on blog_members (source_id);
    18 create index blog_members_dest on blog_members (dest_id);
  • utf8/plugins/blogs/sql/TOAST/blog_tag_cloud.sql

     
    1 create table blog_tag_cloud
    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 status smallint not null default 1,
    8 source_id integer not null,
    9 source_class text default 'blogs::Tag',
    10 dest_id integer not null,
    11 dest_class text not null default 'blogs::Record',
    12 data text
    13 );
    14 create index blog_tag_cloud_source on blog_tag_cloud (source_id);
    15 create index blog_tag_cloud_dest on blog_tag_cloud (dest_id);
  • utf8/plugins/blogs/sql/TOAST/blog_tags.sql

     
    1 create table blog_tags
    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 status smallint not null default 0,
    8 uid integer not null,
    9 sections integer,
    10 name text,
    11 rate integer default 0,
    12 data text
    13 );
    14 create index blog_tags_sections on blog_tags (sections);
    15 create index blog_tags_uid on blog_tags (uid);
  • utf8/plugins/blogs/sql/TOAST/blogs.sql

     
    1 create table blogs
    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 not null default now(),
    8 status smallint not null default 0,
    9 type smallint default 0,
    10 uid integer not null,
    11 sections integer[],
    12 name text,
    13 records integer default 0,
    14 readers integer[],
    15 members integer[],
    16 moderators integer[],
    17 data text
    18 );
    19 create index blogs_sections on blogs using gist ( "sections" "gist__int_ops" );
    20 create index blogs_members on blogs using gist ( "members" "gist__int_ops" );
    21 create index blogs_moderators on blogs using gist ( "moderators" "gist__int_ops" );
    22 create index blogs_dtime on blogs (dtime);
    23 create index blogs_uid on blogs (uid);
  • utf8/plugins/blogs/sql/TOAST/comments.sql

     
    1 create table blog_comments
    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 not null default now(),
    8 status smallint not null default 0,
    9 type smallint default 0,
    10 uid integer not null,
    11 blog_id integer not null,
    12 record_id integer not null,
    13 pid integer default 0,
    14 sections integer[],
    15 name text,
    16 data text
    17 );
    18 create index blog_comments_sections on blog_comments using gist ( "sections" "gist__int_ops" );
    19 create index blog_comments_dtime on blog_comments (dtime);
    20 create index blog_comments_uid on blog_comments (uid);
    21 create index blog_comments_record_id on blog_comments (record_id);
  • utf8/plugins/blogs/sql/TOAST/records.sql

     
    1 create table blog_records
    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 not null default now(),
    8 status smallint not null default 0,
    9 uid integer not null,
    10 blog_id integer not null,
    11 sections integer[],
    12 name text,
    13 comments integer default 0,
    14 tags text,
    15 data text
    16 );
    17 create index blog_records_sections on blog_records using gist ( "sections" "gist__int_ops" );
    18 create index blog_records_dtime on blog_records (dtime);
    19 create index blog_records_uid on blog_records (uid);
    20 create index blog_records_blog_id on blog_records (blog_id);

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

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

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

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

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