Revision 217
Date:
2012/06/16 14:31:03
Author:
ahitrov
Revision Log:
1. New serializer (JSON) and project param-key
SERIALIZE_WITH = dumper|json
2. New port version
3. Plugin Skeleton updated
4. Text pre-formatting for WYSIWYG
Files:
Legend:
Added
Removed
Modified
utf8/core/comps/contenido/components/inputs/wysiwyg.msn
12
12
% if ($request->{images_staff_printed}) {
13
13
onclick="storeCaret(this)" onkeyup="storeCaret(this)" onselect="storeCaret(this)" \
14
14
% }
15
<% $prop->{readonly} ? 'readonly ' : '' %> name="<% $name %>" rows="<% $prop->{rows} || 8 %>" cols="<% $prop->{cols} || 8 %>" style="width: 95%;"><% $check %></textarea>
15
<% $prop->{readonly} ? 'readonly ' : '' %> name="<% $name %>" rows="<% $prop->{rows} || 8 %>" cols="<% $prop->{cols} || 8 %>" style="width: 95%;"><& /inc/text_format.msn, text => $check &></textarea>
16
16
17
17
<%args>
18
18
$name => undef
…
…
21
21
$object => undef
22
22
</%args>
23
23
<%init>
24
$check = html_escape($check) unless $prop->{no_escape};
25
24
</%init>
utf8/core/GNUmakefile
1208
1208
PGSQL_ENCODE_DATA \
1209
1209
PGSQL_DECODE_DATA \
1210
1210
PGSQL_ENABLE_UTF \
1211
SERIALIZE_WITH \
1211
1212
PLUG_SRC \
1212
1213
PLUGINS \
1213
1214
PLUGIN_COMP \
utf8/core/lib/Contenido/File.pm
113
113
#убираем начальный /
114
114
$filename =~ s#^/##;
115
115
116
my $success = 0;
116
117
foreach my $dir (@{$state->{"files_dir"}}) {
117
no strict "refs";
118
&{"Contenido::File::Scheme::".uc(scheme($dir))."::remove"}($dir."/".$filename);
118
no strict "refs";
119
my $scheme = uc(scheme($dir));
120
my $res;
121
if ( !$success || $scheme eq 'FILE' ) {
122
$res = &{"Contenido::File::Scheme::".$scheme."::remove"}($dir."/".$filename);
123
}
124
if ( $res && $scheme eq 'HTTP' && $state->{file_web_storage} eq 'common' ) {
125
$success = 1;
126
}
119
127
}
120
128
121
129
1;
utf8/core/lib/Contenido/Keeper.pm
57
57
$self->{db_client_encoding} = $local_state->{attributes}{db_client_encoding} ? $local_state->db_client_encoding() : '';
58
58
$self->{db_enable_utf8} = $local_state->{attributes}{db_enable_utf8} ? $local_state->db_enable_utf8() : 0;
59
59
60
$self->{serialize_with} = $local_state->{serialize_with};
61
60
62
$self->{data_dir} = $self->{data_directory} = $local_state->data_directory();
61
63
$self->{images_dir} = $self->{images_directory} = $local_state->images_directory();
62
64
$self->{binary_dir} = $self->{binary_directory} = $local_state->binary_directory();
…
…
95
97
96
98
foreach my $attribute ( qw(
97
99
db_host db_name db_user db_password db_port
100
serialize_with
98
101
99
102
data_directory data_dir
100
103
images_directory images_dir
…
…
313
316
$self->set_object_to_cache($item, 30, $opts) if ($opts->{with_cache});
314
317
$total++;
315
318
if ( exists $item->{$hash_by} && defined $item->{$hash_by} ) {
316
$items{$item->{$hash_by}} = $item;
319
$items{$item->{$hash_by}} = $item;
317
320
} else {
318
$log->warning( "Can not HASH BY parameter [$hash_by]. It doesn't exists in row or the field is empty");
321
$log->warning( "Can not HASH BY parameter [$hash_by]. It doesn't exists in row or the field is empty");
319
322
}
320
323
}
321
324
}
utf8/core/lib/Contenido/Object.pm
20
20
use Contenido::Globals;
21
21
use Contenido::File;
22
22
use Data::Dumper;
23
use Data::Recursive::Encode;
24
use JSON::XS;
23
25
24
26
use DBD::Pg;
25
27
use Encode;
26
28
27
29
use SQL::ProtoTable;
28
30
31
our $json_n = JSON::XS->new->utf8(0);
32
our $json_u = JSON::XS->new->utf8(1);
33
29
34
# required properties теперь берутся из свойств таблицы
30
35
sub required_properties {
31
36
my $self=shift;
…
…
219
224
$virtual_fields{$attr} = 1;
220
225
} else {
221
226
#инициализируем из dump все кроме виртуальных свойств
222
push @funct_exra_fields, "$attr=>$func_start_encode\$dump->{$attr}$func_end_encode";
227
push @funct_exra_fields, "$attr=>(\$keeper->serialize_with eq 'json' ? Encode::encode('utf-8', \$dump->{$attr}, Encode::FB_HTMLCREF) : $func_start_encode\$dump->{$attr}$func_end_encode)";
223
228
}
224
229
}
225
230
}
…
…
234
239
# Чтение из одного дампа в базе данных
235
240
# --------------------------------------------------------------------------------------------
236
241
my $funct_eval_dump .= '
237
my $dump = Contenido::Object::eval_dump(\\$row->[-1]);
242
my $dump = $keeper->serialize_with eq \'json\' ? (Contenido::Object::eval_json(\\$row->[-1]) || {}) : Contenido::Object::eval_dump(\\$row->[-1]);
238
243
';
239
244
$funct = $funct_begin.$funct_begin_if_light.$funct_start_obj.join(', ', @funct_default_fields).$funct_end_obj.$funct_elsif_light.$funct_eval_dump.$funct_start_obj.join(', ', (@funct_default_fields, @funct_exra_fields)).$funct_end_obj.$funct_endif_light;
240
245
} else {
241
246
$funct = $funct_begin.$funct_start_obj.join(', ', @funct_default_fields).$funct_end_obj;
242
247
}
248
# warn "Restore function: [$funct]\n";
243
249
244
250
create_method($class, 'init_from_db', $funct);
245
251
…
…
299
305
300
306
my $extra_fields = [];
301
307
my $virtual_fields = {};
302
{
308
309
if ( $self->keeper->serialize_with eq 'json' ) {
303
310
no strict 'refs';
304
local $Data::Dumper::Indent = 0;
305
311
#пропускаем virtual attributes
306
312
#да я знаю что так писать нельзя но блин крута как смотрится
307
313
$extra_fields = ${$self->{class}.'::extra_fields'};
308
314
$virtual_fields = ${$self->{class}.'::virtual_fields'};
309
315
#надо использовать все extra поля кроме тех что находятся в virtual_fields списке
310
316
if ($state->db_encode_data) {
317
return Encode::decode('utf-8', $json_n->encode ({map { $_=> Encode::decode($state->db_encode_data, $self->{$_}, Encode::FB_HTMLCREF) } grep { !$virtual_fields->{$_} && (defined $self->{$_}) } @$extra_fields}));
318
} else {
319
my $content = Encode::decode('utf-8', $json_n->encode ({map { $_=>$self->{$_} } grep { !$virtual_fields->{$_} && (defined $self->{$_}) } @$extra_fields}));
320
# warn "Store content is [$content]. UTF-8 Flag [".Encode::is_utf8($content)."]\n";
321
return $content;
322
}
323
} else {
324
no strict 'refs';
325
#пропускаем virtual attributes
326
#да я знаю что так писать нельзя но блин крута как смотрится
327
$extra_fields = ${$self->{class}.'::extra_fields'};
328
$virtual_fields = ${$self->{class}.'::virtual_fields'};
329
#надо использовать все extra поля кроме тех что находятся в virtual_fields списке
330
local $Data::Dumper::Indent = 0;
331
if ($state->db_encode_data) {
311
332
return Data::Dumper::Dumper({map { $_=> Encode::decode($state->db_encode_data, $self->{$_}, Encode::FB_HTMLCREF) } grep { !$virtual_fields->{$_} && (defined $self->{$_}) } @$extra_fields});
312
333
} else {
313
334
return Data::Dumper::Dumper({map { $_=>$self->{$_} } grep { !$virtual_fields->{$_} && (defined $self->{$_}) } @$extra_fields});
…
…
334
355
# --------------------------------------------------------------------------------------------
335
356
# Чтение из одного дампа в базе данных
336
357
# --------------------------------------------------------------------------------------------
337
my $dump_ = eval_dump(\$row->[-1]);
358
my $dump_ = $self->keeper->serialize_with eq 'json' ? eval_json(\$row->[-1]) : eval_dump(\$row->[-1]);
338
359
if ($dump_) {
339
360
foreach (@$extra_fields) {
340
361
$self->{$_} = $dump_->{$_};
…
…
347
368
}
348
369
}
349
370
371
sub _serialize {
372
my $self = shift;
373
my $data = shift;
374
if ( $self->keeper->serialize_with eq 'json' ) {
375
return $json_n->encode($data);
376
} else {
377
local $Data::Dumper::Indent = 0;
378
return Data::Dumper::Dumper($data);
379
}
380
}
381
350
382
# ----------------------------------------------------------------------------
351
383
# Выбирает хеш из перл-дампа по атрибуту
352
384
# Пример:
…
…
355
387
sub get_data {
356
388
my $self = shift;
357
389
my $attr = shift;
358
my $data = eval_dump(\$self->{$attr});
390
my $encode = shift;
391
my $data = $self->keeper->serialize_with eq 'json' ? ( $encode ? Data::Recursive::Encode->encode_utf8(eval_json(\$self->{$attr})) : eval_json(\$self->{$attr}) ) : eval_dump(\$self->{$attr});
359
392
return ($data || {});
360
393
}
361
394
…
…
372
405
my $attr = shift;
373
406
374
407
Contenido::Image->new (
375
img => $self->get_data($attr),
408
img => $self->get_data($attr, 'encode'),
376
409
attr => $attr,
377
410
);
378
411
}
…
…
392
425
my $self = shift;
393
426
my $attr = shift;
394
427
my %args = ref $_[0] ? %{$_[0]} : @_;
395
my $pics = $self->get_data($attr);
428
my $pics = $self->get_data($attr, 'encode');
396
429
397
430
# Дефолты
398
431
$args{order} ||= 'direct';
…
…
459
492
foreach ($self->required_properties()) {
460
493
461
494
my $value = $self->{$_->{attr}};
462
$value = undef if (defined($value) and $value eq '') and (lc($_->{db_type}) eq 'float' or lc($_->{db_type} eq 'integer'));
463
$value = undef if lc $_->{db_type} eq 'integer[]' && ref $value ne 'ARRAY';
464
$value = undef if lc $_->{db_type} eq 'integer_ref[]' && ref $value ne 'ARRAY';
495
if ( exists $_->{db_field} && $_->{db_field} ) {
496
$value = undef if (defined($value) and $value eq '') and (lc($_->{db_type}) eq 'float' or lc($_->{db_type} eq 'integer'));
497
$value = undef if lc $_->{db_type} eq 'integer[]' && ref $value ne 'ARRAY';
498
$value = undef if lc $_->{db_type} eq 'integer_ref[]' && ref $value ne 'ARRAY';
499
}
465
500
466
501
#пропустить readonly если у документа уже есть id
467
502
if ($self->id() and $_->{readonly}) {
…
…
993
1028
return eval ${$_[0]};
994
1029
}
995
1030
1031
sub eval_json {
1032
return undef unless ${$_[0]};
1033
my $value = $json_u->decode( ${$_[0]});
1034
# map { $_ = Encode::encode(\'utf-8\', $_) unless ref $_; } values %$value;
1035
return $value;
1036
}
1037
996
1038
sub create_method {
997
1039
my ($class, $sub_name, $code) = @_;
998
1040
…
…
1069
1111
# оставлена для обратной совместимости...
1070
1112
sub get_image {
1071
1113
my $self = shift;
1072
$self->get_data(shift);
1114
if ( $self->keeper->serialize_with eq 'json' ) {
1115
return $self->get_data(shift, 'encode');
1116
} else {
1117
return $self->get_data(shift);
1118
}
1073
1119
}
1074
1120
1075
1121
sub raw_restore {
utf8/core/lib/Contenido/State.pm.proto
42
42
$self->{db_encode_data} = '@PGSQL_ENCODE_DATA@';
43
43
$self->{db_decode_data} = '@PGSQL_DECODE_DATA@' || 'utf-8';
44
44
45
$self->{serialize_with} = lc('@SERIALIZE_WITH@') || 'dumper';
46
45
47
$self->{master_db_host} = (($self->{db_type} eq 'remote') and '@MASTER_BASE_HOST@') ? lc('@MASTER_BASE_HOST@') : 'localhost';
46
48
$self->{master_db_name} = '@MASTER_BASE_NAME@';
47
49
$self->{master_db_user} = '@MASTER_BASE_USER@';
…
…
231
233
232
234
stage
233
235
db_keepalive db_host db_name db_user db_password db_port db_type db_client_encoding db_enable_utf8
234
235
236
db_encode_data db_decode_data
236
237
237
238
mason_comp
utf8/core/ports/all/common-sense/GNUmakefile
5
5
6
6
include ../../etc/perl.mk
7
7
8
PORTVERSION = 3.4
8
PORTVERSION = 3.5
9
9
PERL_MAKEMAKER = yes
10
10
MASTER_CPAN_SUBDIR = ../../authors/id/M/ML/MLEHMANN
11
11
utf8/core/project-default.mk
34
34
35
35
# additional ports if any
36
36
PROJECT_REQUIRED ?=
37
SERIALIZE_WITH ?=
37
38
38
39
# defaults
39
40
PRELOADS ?=
utf8/core/skel/plugin/lib/plugin/State.pm.proto
11
11
my $self = {};
12
12
bless $self, $class;
13
13
14
# configured
15
$self->{debug} = (lc('@DEBUG@') eq 'yes');
16
$self->{project} = '@PROJECT@';
17
14
18
# зашитая конфигурация плагина
15
# $self->{db_type} = 'remote';
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} = '';
19
$self->{db_type} = 'none'; ### For REAL database use 'remote'
20
$self->{db_keepalive} = 0;
21
$self->{db_host} = '';
22
$self->{db_name} = '';
23
$self->{db_user} = '';
24
$self->{db_password} = '';
25
$self->{db_port} = '';
26
$self->{store_method} = 'toast';
27
$self->{cascade} = 1;
28
$self->{db_prepare} = 0;
22
29
30
$self->{memcached_enable} = lc( '@MEMCACHED_ENABLE@' ) eq 'yes' ? 1 : 0;
31
$self->{memcached_enable_compress} = 1;
32
$self->{memcached_backend} = '@MEMCACHED_BACKEND@';
33
$self->{memcached_servers} = [qw(@MEMCACHED_SERVERS@)];
34
$self->{memcached_busy_lock} = 60;
35
$self->{memcached_delayed} = lc('@MEMCACHED_DELAYED@') eq 'yes' ? 1 : 0;
36
37
$self->{serialize_with} = 'json'; ### or 'dumper'
38
39
# not implemented really (core compatibility)
40
$self->{binary_directory} = '/nonexistent';
41
$self->{data_directory} = '/nonexistent';
42
$self->{images_directory} = '/nonexistent';
43
$self->{preview} = '0';
44
23
45
$self->_init_();
24
46
$self;
25
47
}
…
…
39
61
40
62
# зашитая конфигурация плагина
41
63
$self->{attributes}->{$_} = 'SCALAR' for qw(
42
# db_type
43
# db_keepalive
44
# db_host
45
# db_port
46
# db_name
47
# db_user
48
# db_password
64
debug
65
project
66
67
db_type
68
db_keepalive
69
db_host
70
db_port
71
db_name
72
db_user
73
db_password
74
store_method
75
cascade
76
db_prepare
77
db_client_encoding
78
79
memcached_enable
80
memcached_enable_compress
81
memcached_backend
82
memcached_servers
83
memcached_busy_lock
84
memcached_delayed
85
86
binary_directory
87
data_directory
88
images_directory
89
preview
49
90
);
50
91
}
51
92
Небольшая справка по веткам
cnddist – контейнер, в котором хранятся все дистрибутивы всех библиотек и программных пакетов, которые использовались при построении различных версий Contenido. Если какой-то библиотеки в данном хранилище нет, инсталлятор сделает попытку "подтянуть" ее с веба (например, с CPAN). Если библиотека слишком старая, есть очень большая вероятность, что ее там уже нет. Поэтому мы храним весь хлам от всех сборок. Если какой-то дистрибутив вдруг отсутствует в cnddist - напишите нам, мы положим его туда.
koi8 – отмирающая ветка, чей код, выдача и все внутренние библиотеки заточены на кодировку KOI8-R. Вносятся только те дополнения, которые касаются внешнего вида и функционала админки, баги ядра, обязательные обновления портов и мелочи, которые легко скопипастить. В дальнейшем планируется полная остановка поддержки по данной ветке.
utf8 – актуальная ветка, заточенная под UTF-8.
Внутри каждой ветки: core – исходники ядра; install – скрипт установки инсталляции; plugins – плагины; samples – "готовые к употреблению" проекты, которые можно поставить, запустить и посмотреть, как они работают.