Revision 234
- Date:
- 2012/08/28 09:26:59
- Files:
-
- /utf8/plugins/blogs/comps
- /utf8/plugins/blogs/comps/contenido
- /utf8/plugins/blogs/comps/contenido/blogs
- /utf8/plugins/blogs/comps/contenido/blogs/autohandler (Diff) (Checkout)
- /utf8/plugins/blogs/comps/contenido/blogs/dhandler (Diff) (Checkout)
- /utf8/plugins/blogs/comps/contenido/blogs/index.html (Diff) (Checkout)
- /utf8/plugins/blogs/lib
- /utf8/plugins/blogs/lib/blogs
- /utf8/plugins/blogs/lib/blogs/Apache.pm (Diff) (Checkout)
- /utf8/plugins/blogs/lib/blogs/Blog.pm (Diff) (Checkout)
- /utf8/plugins/blogs/lib/blogs/BlogSection.pm (Diff) (Checkout)
- /utf8/plugins/blogs/lib/blogs/Comment.pm (Diff) (Checkout)
- /utf8/plugins/blogs/lib/blogs/Init.pm (Diff) (Checkout)
- /utf8/plugins/blogs/lib/blogs/Keeper.pm (Diff) (Checkout)
- /utf8/plugins/blogs/lib/blogs/MemberLink.pm (Diff) (Checkout)
- /utf8/plugins/blogs/lib/blogs/Record.pm (Diff) (Checkout)
- /utf8/plugins/blogs/lib/blogs/RecordSection.pm (Diff) (Checkout)
- /utf8/plugins/blogs/lib/blogs/SQL
- /utf8/plugins/blogs/lib/blogs/SQL/BlogsTable.pm (Diff) (Checkout)
- /utf8/plugins/blogs/lib/blogs/SQL/CommentsTable.pm (Diff) (Checkout)
- /utf8/plugins/blogs/lib/blogs/SQL/MembersTable.pm (Diff) (Checkout)
- /utf8/plugins/blogs/lib/blogs/SQL/RecordsTable.pm (Diff) (Checkout)
- /utf8/plugins/blogs/lib/blogs/SQL/TagCloudTable.pm (Diff) (Checkout)
- /utf8/plugins/blogs/lib/blogs/SQL/TagsTable.pm (Diff) (Checkout)
- /utf8/plugins/blogs/lib/blogs/State.pm.proto (Diff) (Checkout)
- /utf8/plugins/blogs/lib/blogs/SubscriberLink.pm (Diff) (Checkout)
- /utf8/plugins/blogs/lib/blogs/Tag.pm (Diff) (Checkout)
- /utf8/plugins/blogs/lib/blogs/TagCloud.pm (Diff) (Checkout)
- /utf8/plugins/blogs/lib/blogs/TagSection.pm (Diff) (Checkout)
- /utf8/plugins/blogs/sql
- /utf8/plugins/blogs/sql/TOAST
- /utf8/plugins/blogs/sql/TOAST/blog_members.sql (Diff) (Checkout)
- /utf8/plugins/blogs/sql/TOAST/blog_tag_cloud.sql (Diff) (Checkout)
- /utf8/plugins/blogs/sql/TOAST/blog_tags.sql (Diff) (Checkout)
- /utf8/plugins/blogs/sql/TOAST/blogs.sql (Diff) (Checkout)
- /utf8/plugins/blogs/sql/TOAST/comments.sql (Diff) (Checkout)
- /utf8/plugins/blogs/sql/TOAST/records.sql (Diff) (Checkout)
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);