Revision 474

Date:
2015/02/25 13:22:42
Author:
ahitrov
Revision Log:
Tags plugin

Files:

Legend:

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

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

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

     
    1 <& "/contenido/components/header.msn" &>
    2 <& "/contenido/components/naviline.msn" &>
    3
    4 <p>PLugin [tags]</p>
    5
    6 </body>
    7 </html>
  • utf8/plugins/tags/config.proto

     
    1 #############################################################################
    2 #
    3 # Параметры данного шаблона необходимо ВРУЧНУЮ добавить в config.mk проекта
    4 # и привести в соответствие с требованиями проекта
    5 #
    6 #############################################################################
    7
    8 PLUGINS += tags
    9
    10 TAGS_DEST = <список через пробел классов тегируемых документов>
    11 REWRITE += TAGS_DEST
  • utf8/plugins/tags/lib/tags/Apache.pm

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

     
    1 package zvukiru::TagLink;
    2
    3 use base 'Contenido::Link';
    4
    5 sub class_name
    6 {
    7 return 'Тег к объекту';
    8 }
    9
    10 sub class_description
    11 {
    12 return 'Организация облака тегов';
    13 }
    14
    15 sub extra_properties
    16 {
    17 return (
    18 );
    19 }
    20
    21 sub available_sources
    22 {
    23 return [ qw(tags::Tag) ];
    24 }
    25
    26 sub available_destinations
    27 {
    28 return $state->{tags}->tags_destinations;
    29 }
    30
    31 sub class_table
    32 {
    33 return 'tags::SQL::TagsCloudTable';
    34 }
    35
    36 sub pre_store
    37 {
    38 my $self = shift;
    39
    40 return 1;
    41 }
    42
    43 1;
  • utf8/plugins/tags/lib/tags/Init.pm

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

     
    1 package tags::Keeper;
    2
    3 use strict;
    4 use warnings 'all';
    5 use base qw(Contenido::Keeper);
    6
    7
    8 use Contenido::Globals;
    9
    10
    11 1;
  • utf8/plugins/tags/lib/tags/Section.pm

     
    1 package tags::Section;
    2
    3 use base 'Contenido::Section';
    4
    5 sub extra_properties
    6 {
    7 return (
    8 { 'attr' => 'default_document_class', 'default' => 'tags::Tag' },
    9 )
    10 }
    11
    12 sub class_name
    13 {
    14 return 'Секция тегов';
    15 }
    16
    17 sub class_description
    18 {
    19 return 'Секция тегов';
    20 }
    21
    22 1;
  • utf8/plugins/tags/lib/tags/SQL/TagsCloudTable.pm

     
    1 package tags::SQL::TagsCloudTable;
    2
    3 use strict;
    4 use base 'SQL::LinkTable';
    5
    6 sub db_table
    7 {
    8 return 'tags_cloud';
    9 }
    10
    11 # ----------------------------------------------------------------------------
    12 # Свойства храним в массивах, потому что порядок важен!
    13 # Это общие свойства - одинаковые для всех документов.
    14 #
    15 # attr - обязательный параметр, название атрибута;
    16 # type - тип аттрибута, требуется для отображдения;
    17 # rusname - русское название, опять же требуется для отображения;
    18 # hidden - равен 1, когда
    19 # readonly - инициализации при записи только без изменения в дальнейшем
    20 # db_field - поле в таблице
    21 # default - значение по умолчанию (поле всегда имеет это значение)
    22 # ----------------------------------------------------------------------------
    23 sub required_properties
    24 {
    25 my $self = shift;
    26
    27 my @parent_properties = $self->SUPER::required_properties;
    28 return (
    29 @parent_properties,
    30 );
    31 }
    32
    33 ########### FILTERS DESCRIPTION ####################################################################################
    34
    35 1;
    36
  • utf8/plugins/tags/lib/tags/SQL/TagsTable.pm

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

     
    1 package tags::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 # configured
    15 $self->{project} = '@PROJECT@';
    16 $self->{debug} = (lc('@DEBUG@') eq 'yes');
    17 $self->{contenido_notab} = 0;
    18 $self->{tab_name} = 'Теги';
    19 $self->{project_name} = '@PROJECT_NAME@';
    20 $self->{default_expire} = '@DEFAULT_EXPIRE@' || 300;
    21 $self->{default_object_expire} = '@DEFAULT_OBJECT_EXPIRE@' || 600;
    22
    23 # зашитая конфигурация плагина
    24 $self->{db_type} = 'none'; ### For REAL database use 'remote'
    25 $self->{db_keepalive} = 0;
    26 $self->{db_host} = '';
    27 $self->{db_name} = '';
    28 $self->{db_user} = '';
    29 $self->{db_password} = '';
    30 $self->{db_port} = '';
    31 $self->{store_method} = 'toast';
    32 $self->{cascade} = 1;
    33 $self->{db_prepare} = 0;
    34
    35 $self->{memcached_enable} = lc( '@MEMCACHED_ENABLE@' ) eq 'yes' ? 1 : 0;
    36 $self->{memcached_backend} = '@MEMCACHED_BACKEND@';
    37 $self->{memcached_select_timeout} = '@MEMCACHED_SELECT_TIMEOUT@' || 0.2;
    38 $self->{memcached_servers} = [qw(@MEMCACHED_SERVERS@)];
    39 $self->{memcached_enable_compress} = lc( '@MEMCACHED_ENABLE_COMPRESS@' ) eq 'yes' ? 1 : 0;
    40 $self->{memcached_delayed} = lc('@MEMCACHED_DELAYED@') eq 'yes' ? 1 : 0;
    41 $self->{memcached_set_mode} = lc('@MEMCACHED_SET_MODE@') eq 'add' ? 'add' : 'set';
    42 $self->{memcached_busy_lock} = 60;
    43 $self->{memcached_namespace} = lc( $self->{'project'} ).'|plugin_tags|';
    44
    45 $self->{serialize_with} = 'json'; ### or 'dumper'
    46
    47 # not implemented really (core compatibility)
    48 $self->{data_directory} = '';
    49 $self->{images_directory} = '';
    50 $self->{binary_directory} = '';
    51 $self->{preview} = '';
    52
    53 $self->{tags_destinations} = [qw(@TAGS_DEST@)]
    54
    55 $self->_init_();
    56 $self;
    57 }
    58
    59 sub info {
    60 my $self = shift;
    61 return unless ref $self;
    62
    63 for (sort keys %{$self->{attributes}}) {
    64 my $la = length $_;
    65 warn "\t$_".("\t" x (2-int($la/8))).": $self->{$_}\n";
    66 }
    67 }
    68
    69 sub _init_ {
    70 my $self = shift;
    71
    72 # зашитая конфигурация плагина
    73 $self->{attributes}->{$_} = 'SCALAR' for qw(
    74 debug
    75 project
    76 tab_name
    77
    78 db_type
    79 db_keepalive
    80 db_host
    81 db_port
    82 db_name
    83 db_user
    84 db_password
    85 store_method
    86 cascade
    87 db_prepare
    88 db_client_encoding
    89
    90 memcached_enable
    91 memcached_servers
    92 memcached_select_timeout
    93 memcached_backend
    94 memcached_enable_compress
    95 memcached_set_mode
    96 memcached_object_expire
    97 memcached_busy_lock
    98 memcached_delayed
    99 memcached_namespace
    100
    101 binary_directory
    102 data_directory
    103 images_directory
    104 preview
    105
    106 tags_destinations
    107 );
    108 }
    109
    110 sub AUTOLOAD {
    111 my $self = shift;
    112 my $attribute = $AUTOLOAD;
    113
    114 $attribute =~ s/.*:://;
    115 return unless $attribute =~ /[^A-Z]/; # Отключаем методы типа DESTROY
    116
    117 if (!exists $self->{attributes}->{$attribute}) {
    118 warn "Contenido Error (tags::State): Вызов метода, для которого не существует обрабатываемого свойства: ->$attribute()\n";
    119 return;
    120 }
    121
    122 $self->{$attribute} = shift @_ if $#_>=0;
    123 $self->{$attribute};
    124 }
    125
    126 1;
  • utf8/plugins/tags/lib/tags/Tag.pm

     
    1 package tags::Tag;
    2
    3 use base 'Contenido::Document';
    4 use Contenido::Globals;
    5
    6 sub extra_properties
    7 {
    8 return (
    9 { 'attr' => 'name', 'rusname' => 'Название тега', shortname => 'Тег' },
    10 )
    11 }
    12
    13
    14 sub class_name
    15 {
    16 return 'Тег';
    17 }
    18
    19 sub class_description
    20 {
    21 return 'Тег';
    22 }
    23
    24 sub class_table
    25 {
    26 return 'tags::SQL::TagsTable';
    27 }
    28
    29 sub search_fields {
    30 return ('name');
    31 }
    32
    33 sub pre_store
    34 {
    35 my $self = shift;
    36
    37 my $default_section = $project->s_alias->{tags} if ref $project->s_alias eq 'HASH' && exists $project->s_alias->{tags};
    38 $self->sections( $default_section ) if $default_section;
    39
    40 return 1;
    41 }
    42
    43
    44 1;
  • utf8/plugins/tags/sql/TOAST/tags.sql

     
    1 create table tags
    2 (
    3 id integer not null primary key default nextval('public.documents_id_seq'::text),
    4 ctime timestamp not null default now(),
    5 mtime timestamp not null default now(),
    6 class text not null,
    7 status smallint not null default 0,
    8 sections integer,
    9 name text,
    10 alias text,
    11 data text
    12 );
    13 create index tags_name on tags (name);
    14 create index tags_alias on tags (alias) WHERE alias IS NOT NULL AND alias != '';
  • utf8/plugins/tags/sql/TOAST/tags_cloud.sql

     
    1 create table tags_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 not null default 'tags::Tag',
    10 dest_id integer not null,
    11 dest_class text not null,
    12 data text
    13 );
    14 create index tags_cloud_source on tags_cloud (source_id);
    15 create index tags_cloud_dest on tags_cloud (dest_id);