Annotation of db/prgsrc/db.cgi, revision 1.31
1.29 roma7 1: #!/usr/bin/perl -w
1.1 boris 2:
3: use DBI;
4: use CGI ':all';
1.15 roma7 5: use Text::Query;
1.1 boris 6: use strict;
7: use Time::Local;
8: use POSIX qw(locale_h);
1.22 roma7 9: use locale;
10: open STDERR, ">errors";
1.29 roma7 11: my $printqueries=1;
12: my $debug=1; #added by R7
1.25 roma7 13: my %fieldname= (0,'Question', 1, 'Answer', 2, 'Comments', 3, 'Authors', 4, 'Sources');
1.22 roma7 14: my %searchin;
15:
16:
17:
18: my $thislocale;
19:
20:
1.23 roma7 21: $searchin{'question'}=param('Question');
22: $searchin{'answer'}=param('Answer');
23: $searchin{'comment'}=param('Comment');
1.25 roma7 24: $searchin{'authors'}=param('Authors');
25: $searchin{'sources'}=param('Sources');
1.22 roma7 26: my $all=param('all');
27: $all=0 if lc $all eq 'no';
1.1 boris 28: my ($PWD) = `pwd`;
29: chomp $PWD;
1.3 boris 30: my ($SRCPATH) = "$PWD/../dimrub/src";
1.8 boris 31: my ($ZIP) = "/home/piataev/bin/zip";
1.11 boris 32: my $DUMPFILE = "/tmp/chgkdump";
1.1 boris 33: my ($SENDMAIL) = "/usr/sbin/sendmail";
34: my ($TMSECS) = 30*24*60*60;
35: my (%RevMonths) =
36: ('Jan', '0', 'Feb', '1', 'Mar', '2', 'Apr', '3', 'May', '4', 'Jun', '5',
37: 'Jul', '6', 'Aug', '7', 'Sep', '8', 'Oct', '9', 'Nov', '10',
1.3 boris 38: 'Dec', '11',
39: 'Янв', '0', 'Фев', 1, 'Мар', 2, 'Апр', 3, 'Май', '4',
40: 'Июн', '5', 'Июл', 6, 'Авг', '7', 'Сен', '8',
41: 'Окт', '9', 'Ноя', '19', 'Дек', '11');
1.1 boris 42:
43: # Determine whether the given time is within 2 months from now.
44: sub NewEnough {
45: my ($a) = @_;
46: my ($year, $month, $day) = split('-', $a);
47:
48: return (time - timelocal(0, 0, 0, $day, $month -1, $year) < $TMSECS);
49: }
50:
51: # Reads one question from the DB. Gets DB handler and Question ID.
52: sub GetTournament {
53: my ($dbh, $Id) = @_;
54: my (%Tournament, $field, @arr);
55:
56: return %Tournament if ($Id == 0);
57:
58: my ($sth) = $dbh->prepare("SELECT * FROM Tournaments WHERE Id=$Id");
59: $sth->execute;
60:
61: @arr = $sth->fetchrow;
62: my($i, $name) = 0;
63: foreach $name (@{$sth->{NAME}}) {
64: $Tournament{$name} = $arr[$i++];
65: }
66:
67: return %Tournament;
68: }
69:
70: # Reads one question from the DB. Gets DB handler and Question ID.
71: sub GetQuestion {
72: my ($dbh, $QuestionId) = @_;
73: my (%Question, $field, @arr);
74:
75: my($sth) = $dbh->prepare("
76: SELECT * FROM Questions WHERE QuestionId=$QuestionId
77: ");
78:
79: $sth->execute;
80:
81: @arr = $sth->fetchrow;
82: my($i, $name) = 0;
83: foreach $name (@{$sth->{NAME}}) {
84: $Question{$name} = $arr[$i++];
85: }
86:
87: return %Question;
88: }
89:
90: # Gets numbers of all the questions from the given tour.
91: sub GetTourQuestions {
92: my ($dbh, $ParentId) = @_;
93: my (@arr, @Questions);
94:
95: my ($sth) = $dbh->prepare("SELECT QuestionId FROM Questions
96: WHERE ParentId=$ParentId ORDER BY QuestionId");
97:
98: $sth->execute;
99:
100: while (@arr = $sth->fetchrow) {
101: push @Questions, $arr[0];
102: }
103:
104: return @Questions;
105: }
106:
107: # Returns list of children of the given tournament.
108: sub GetTours {
109: my ($dbh, $ParentId) = @_;
110: my (@arr, @Tours);
111:
112: my ($sth) = $dbh->prepare("SELECT Id FROM Tournaments
113: WHERE ParentId=$ParentId ORDER BY Id");
114:
115: $sth->execute;
116:
117: while (@arr = $sth->fetchrow) {
118: push @Tours, $arr[0];
119: }
120:
121: return @Tours;
122: }
123:
1.22 roma7 124: sub russearch {
125: my ($dbh, $sstr, $all,$allnf)=@_;
126: my (@qw,@w,@tasks,$qw,@arr,$nf,$sth,@nf,$w,$where,$e,@where,%good,$i,%where,$from);
127: my($number,@good,$t,$task,@rho,$rank,%rank,$r2,$r1,$word,$n,@last,$good,@words,%number,$taskid);
128: my ($hi, $lo, $wordnumber,$query,$blob,$field,$sf,$ii);
129: my @frequence;
130: my (@arr1,@ar,@sf,@arr2);
131: my %tasks;
132: my $tasks;
133: my @verybad;
134: my %nf;
135: my %tasksof;
136: my %wordsof;
137: my %relevance;
138: my @blob;
139: my %count;
140:
141: $sstr=~tr/йцукенгшщзхъфывапролджэячсмитьбю/ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮ/;
142: @qw=@w =split (' ', uc $sstr);
143:
144: #-----------
145: foreach $i (0..$#w) # заполняем массив @nf начальных форм
146: # $nf[$i] -- ссылка на массив возможных
147: # начальных форм словоформы $i
148: {
149: $qw= $dbh->quote (uc $w[$i]);
150: $query=" select distinct w2 from nests
151: where w1=$qw";
152: print "$query",br if $printqueries;
153: $sth=$dbh -> prepare($query);
154: $sth -> execute;
155: @{$nf[$i]}=();
156: while (@arr = $sth->fetchrow)
157: {
158: push (@{$nf[$i]},$arr[0])
159: }
160: }
161:
1.29 roma7 162:
1.22 roma7 163: my @bad=grep {!$nf[$_]} 0..$#w; # @bad -- номера словоформ,
164: # которых нет в словаре
165:
166: if (@bad) #есть неопознанные словоформы
167: {
168: require "cw.pl";
169: foreach $i(@bad)
170: {
171: if (@arr=checkword($dbh,$w[$i]))
172: {push (@{$nf[$i]}, @arr);}
173: else
174: {push (@verybad,$i);}
175: }
176: }
177: return () if ($all && @verybad);
178:
1.29 roma7 179:
1.22 roma7 180: my $kvo=0;
181: push @$allnf, @{$_} foreach @nf;
1.29 roma7 182: print "nf=@$allnf";
1.22 roma7 183:
184: foreach $i (0..$#w) #запросы в базу...
185: {
186: @arr=@{$nf[$i]} if $nf[$i];
187: @arr2=@arr1=@arr;
188:
189:
190:
191:
192: $_= " word2question.word=".$_. ' ' foreach @arr;
193: $_= " nf.id=".$_. ' ' foreach @arr1;
194:
195: # $_= " nests.w2=".$_. ' ' foreach @arr2;
196: # $query="select w1 from nests where". (join ' OR ', @arr2);
197: #print $query if $printqueries;
198: # $sth=$dbh -> prepare($query);
199: # $sth->execute;
200: # while (@ar=$sth->fetchrow)
201: # {
202: # $ar[0]=~s/(.)/&nocase($1)/ge;
203: # push(@sf,'(?:'.$ar[0].')');
204: # }
205: # $selectshablon=join '|',@sf;
206:
207: #print $selectshablon,br if $printqueries;
208:
209: # $selectshablon=qr/$selectshablon/i;
210:
211:
212:
213:
214: $query="select questions from word2question where". (join ' OR ', @arr);
215: print "$query\n",br if $printqueries;
216:
217: $sth=$dbh -> prepare($query);
218: $sth->execute;
219:
220: @blob=();
221: while (@arr=$sth->fetchrow)
222: {
223: @blob=(@blob,unpack 'C*',$arr[0]);
224: }
225: $query="select number from nf where ".(join ' OR ', @arr1);
226: print "$query\n",br if $printqueries;
227: $sth=$dbh -> prepare($query);
228: $sth->execute;
229:
230: while (@arr=$sth->fetchrow)
231: {
232: $frequence[$i]+=$arr[0];
233: }
234:
235:
236:
237: if (@blob < 4)
238: {
239: $tasksof{$i}=undef;
240: } else
241: {
242: $kvo++;
243: $ii=0;
244: while ($ii<$#blob) # создаём хэш %tasksof, ключи которого --
245: # номера искомых словоформ, а значения --
246: # списки вопросов, в которых есть соответствующа
247: # словоформа.
248: # Каждый список в свою очередь также оформлен в
249: # виде хэша, ключи которого -- номера вопросов,
250: # а значения -- списки номеров вхождений. Вот.
251: {
1.25 roma7 252: ($field,$lo,$hi,$wordnumber)=@blob[$ii..($ii+3)];
1.22 roma7 253: $ii+=4;
254: $number=$lo+$hi*256;
255: $field=$fieldname{$field};
256: if ($searchin{lc $field})
257: {
258: push @{$tasksof{$i}{$number}}, $wordnumber;
259: # дополнили в хэше, висящем на
260: # словоформе $i в %tasksof список
261: # вхождений $i в вопрос $number.
262: push @{$wordsof{$number}{$i}}, $wordnumber;
263: # дополнили в хэше, висящем на
264: # вопросе $number в %wordsof список
265: # вхождений $i в вопрос $number.
266:
267:
268: }
269: } #while ($ii<$#blob)
270: }
271: } #foreach $i
272:
1.29 roma7 273: #print "keys tasksof", join ' ', keys %{$tasksof{0}};
1.22 roma7 274: #Ищем пересечение или объединение списков вопросов (значений %tasksof)
1.29 roma7 275: foreach $sf (keys %tasksof)
1.22 roma7 276: {
277: $count{$_}++ foreach keys %{$tasksof{$sf}};
278: }
279: @tasks= ($all ? (grep {$count{$_}==$kvo} keys %count) :
280: keys %count) ;
281:
282:
1.29 roma7 283: print "\n\$#tasks=",$#tasks,br if $printqueries;
1.22 roma7 284: ############ Сортировка найденных вопросов
285:
286: foreach (keys %wordsof)
287: {
288: $relevance{$_}=&relevance($#w,$wordsof{$_},\@frequence) if $_
289: }
290:
291: @tasks=sort {$relevance{$b}<=>$relevance{$a}} @tasks;
292:
293:
294: ############
295:
1.29 roma7 296: print "tasks=@tasks";
1.22 roma7 297:
298: #print "$_ $relevance{$_} | " foreach @tasks;
299: #print br;
300: print "allnf=@$allnf",br if $printqueries;
301: return @tasks;
302: }
303:
304:
305: sub distance {
306: # на входе -- номера словоформ и ссылки на
307: # списки вхождений. На выходе -- расстояние,
308: # вычисляемое по формуле min(|b-a-pb+pa|)
309: # pb,pa
310: # (pb и pa -- позиции слов b и a)
311: my ($a,$b,$lista,$listb)=@_;
312: my ($pa,$pb,$min,$curmin);
313: $min=10000;
314: foreach $pa (@$lista)
315: {
316: foreach $pb (@$listb)
317: {
318: $curmin=abs($b-$a-$pb+$pa);
319: $min= $curmin if $curmin<$min;
320: }
321: }
322: return $min;
323:
324: }
325:
326: sub relevance {
327: # На входе -- количество искомых словоформ -1 и
328: # ссылка на hash, ключи которого --
329: # номера словоформ, а значения -- списки вхождений
330:
331: my ($n,$words,$frequence)=@_;
332: my $relevance=0;
333: my ($first,$second,$d);
334: foreach $first (0..$n)
335: {
336: $relevance+=scalar @{$$words{$first}}+1000+1000/$$frequence[$first]
337: if $$words{$first};
338: foreach $second ($first+1..$n)
339: {
340: $d=&distance($first,$second,$$words{$first},$$words{$second});
341: $relevance+=($d>10?0:10-$d)*10;
342: }
343: }
344: return $relevance;
345: }
346:
347:
1.1 boris 348:
349: # Returns list of QuestionId's, that have the search string in them.
350: sub Search {
1.22 roma7 351: my ($dbh, $sstr,$metod,$all,$allnf) = @_;
1.1 boris 352: my (@arr, @Questions, @fields);
1.14 roma7 353: my (@sar, $i, $sth,$where);
1.1 boris 354:
1.6 boris 355: # push @fields, 'Question';
1.14 roma7 356:
1.22 roma7 357: if ($metod eq 'rus')
358: {
359: my @tasks=russearch($dbh,$sstr,$all,$allnf);
360: return @tasks
361: }
362:
363:
1.14 roma7 364: ###Simple and advanced query processing. Added by R7
365: if ($metod eq 'simple' || $metod eq 'advanced')
366: {
1.29 roma7 367: foreach (qw/Question Answer Sources Authors Comments/) {
1.14 roma7 368: if (param($_)) {
369: push @fields, $_;
370: }
1.29 roma7 371: }
1.22 roma7 372:
1.14 roma7 373: @fields=(qw/Question Answer Sources Authors Comments/) unless scalar @fields;
374: my $fields=join ",", @fields;
375: my $q=new Text::Query($sstr,
376: -parse => 'Text::Query::'.
377: (($metod eq 'simple') ? 'ParseSimple':'ParseAdvanced'),
378: -solve => 'Text::Query::SolveSQL',
379: -build => 'Text::Query::BuildSQLMySQL',
380: -fields_searched => $fields);
381:
382: $where= $$q{'matchexp'};
383: my $query= "SELECT Questionid FROM Questions
384: WHERE $where";
1.29 roma7 385: print br."Query is: $query".br if $debug;
1.14 roma7 386:
387: $sth = $dbh->prepare($query);
388: } else
389: ######
390: {
391:
392: foreach (qw/Question Answer Sources Authors Comments/) {
1.1 boris 393: if (param($_)) {
394: push @fields, "IFNULL($_, '')";
395: }
1.14 roma7 396: }
397: @sar = split " ", $sstr;
398: for $i (0 .. $#sar) {
1.1 boris 399: $sar[$i] = $dbh->quote("%${sar[$i]}%");
1.14 roma7 400: }
1.1 boris 401:
1.14 roma7 402: my($f) = "CONCAT(" . join(',', @fields) . ")";
403: if (param('all') eq 'yes') {
1.1 boris 404: $sstr = join " AND $f LIKE ", @sar;
1.14 roma7 405: } else {
1.1 boris 406: $sstr = join " OR $f LIKE ", @sar;
1.14 roma7 407: }
1.21 roma7 408:
1.22 roma7 409: my $query="SELECT QuestionId FROM Questions
410: WHERE $f LIKE $sstr ORDER BY QuestionId";
411: print $query if $printqueries;
412: $sth = $dbh->prepare($query)
1.1 boris 413:
1.14 roma7 414: } #else -- processing old-style query (R7)
415:
1.1 boris 416: $sth->execute;
417: while (@arr = $sth->fetchrow) {
418: push @Questions, $arr[0];
419: }
1.22 roma7 420:
1.1 boris 421: return @Questions;
422: }
423:
424: # Substitute every letter by a pair (for case insensitive search).
425: my (@letters) = qw/аА бБ вВ гГ дД еЕ жЖ зЗ иИ йЙ кК лЛ мМ нН оО
426: пП рР сС тТ уУ фФ хХ цЦ чЧ шШ щЩ ьЬ ыЫ эЭ юЮ яЯ/;
427:
428: sub NoCase {
429: my ($sstr) = shift;
430: my ($res);
431:
432: if (($res) = grep(/$sstr/, @letters)) {
433: return "[$res]";
434: } else {
435: return $sstr;
436: }
437: }
438:
439: sub PrintSearch {
1.14 roma7 440: my ($dbh, $sstr, $metod) = @_;
1.22 roma7 441: my @allnf;
442: my (@Questions) = &Search($dbh, $sstr,$metod,$all,\@allnf);
1.1 boris 443: my ($output, $i, $suffix, $hits) = ('', 0, '', $#Questions + 1);
444:
1.22 roma7 445: my $shablon;
446:
447: if ($metod eq 'rus')
448: {
449: my $where='0';
450: $where.= " or w2=$_ " foreach @allnf;
451: my $query="select w1 from nests where $where";
452: my $sth=$dbh->prepare($query);
453: print "$query" if $printqueries;
454:
455: $sth->execute;
456: my @shablon;
457: while (my @arr = $sth->fetchrow)
458: {
459: push @shablon,"(?:$arr[0])";
460: }
461: $shablon= join "|", @shablon;
462: $shablon=~s/[её]/\[ЕЁ\]/gi;
463: # $shablon=~s/([йцукенгшщзхъфывапролджэячсмитьбюЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮ])/&NoCase($1)/ge;
464: $shablon=qr/$shablon/i;
465: print "!$shablon!",br if $printqueries;
466: }
467:
468:
469:
1.1 boris 470: if ($hits =~ /1.$/ || $hits =~ /[5-90]$/) {
471: $suffix = 'й';
472: } elsif ($hits =~ /1$/) {
473: $suffix = 'е';
474: } else {
475: $suffix = 'я';
476: }
477:
478: print p({align=>"center"}, "Результаты поиска на " . strong($sstr)
479: . " : $hits попадани$suffix.");
480:
481: if (param('word')) {
482: $sstr = '[ \.\,:;]' . $sstr . '[ \.\,:\;]';
483: }
484:
485: $sstr =~ s/(.)/&NoCase($1)/ge;
486:
1.13 roma7 487: my(@sar) = split(' ', $sstr);
1.1 boris 488: for ($i = 0; $i <= $#Questions; $i++) {
489: $output = &PrintQuestion($dbh, $Questions[$i], 1, $i + 1, 1);
1.22 roma7 490: if (param('metod') eq 'rus')
491: {
492: $output=~s/\b($shablon)\b/\<strong\>$1\<\/strong\>/gi;
493: } else {
1.1 boris 494: foreach (@sar) {
495: $output =~ s/$_/<strong>$&<\/strong>/gs;
1.22 roma7 496: }}
1.1 boris 497: print $output;
498: }
499: }
500:
501: sub PrintRandom {
502: my ($dbh, $type, $num, $text) = @_;
503: my (@Questions) = &Get12Random($dbh, $type, $num);
504: my ($output, $i) = ('', 0);
505:
506: if ($text) {
507: $output .= " $num случайных вопросов.\n\n";
508: } else {
509: $output .=
510: h2({align=>"center"}, "$num случайных вопросов.");
511: }
512:
513: for ($i = 0; $i <= $#Questions; $i++) {
514: # Passing DB handler, question ID, print answer, question
515: # number, print title, print text/html
516: $output .=
517: &PrintQuestion($dbh, $Questions[$i], 1, $i + 1, 0, $text);
518: }
519: return $output;
520: }
521:
522: sub PrintTournament {
523: my ($dbh, $Id, $answer) = @_;
524: my (%Tournament, @Tours, $i, $list, $qnum, $imgsrc, $alt,
525: $SingleTour);
526: my ($output) = '';
527:
528: %Tournament = &GetTournament($dbh, $Id) if ($Id);
529:
530: my ($URL) = $Tournament{'URL'};
531: my ($Info) = $Tournament{'Info'};
532: my ($Copyright) = $Tournament{'Copyright'};
533:
534: @Tours = &GetTours($dbh, $Id);
535:
536: if ($Id) {
537: for ($Tournament{'Type'}) {
538: /Г/ && do {
539: $output .= h2({align=>"center"},
1.6 boris 540: "Группа: $Tournament{'Title'} ",
541: "$Tournament{'PlayedAt'}") . p . "\n";
1.1 boris 542: last;
543: };
544: /Ч/ && do {
545: return &PrintTour($dbh, $Tours[0], $answer)
546: if ($#Tours == 0);
1.6 boris 547:
548: my $title="Пакет: $Tournament{'Title'}";
549: if ($Tournament{'PlayedAt'}) {
550: $title .= " $Tournament{'PlayedAt'}";
551: }
1.1 boris 552:
553: $output .= h2({align=>"center"},
1.6 boris 554: "$title") . p . "\n";
1.1 boris 555: last;
556: };
557: /Т/ && do {
558: return &PrintTour($dbh, $Id, $answer);
559: };
560: }
561: } else {
562: my ($qnum) = GetQNum($dbh);
563: $output .= h2("Банк Вопросов: $qnum вопросов") . p . "\n";
564: }
565:
566: for ($i = 0; $i <= $#Tours; $i++) {
567: %Tournament = &GetTournament($dbh, $Tours[$i]);
568:
569: if ($Tournament{'Type'} =~ /Ч/) {
570: $SingleTour = 0;
571: my (@Tours) = &GetTours($dbh, $Tournament{'Id'});
572: $SingleTour = 1
573: if ($#Tours == 0);
574: }
575: if ($Tournament{'QuestionsNum'} > 0) {
576: $qnum = " ($Tournament{'QuestionsNum'} вопрос" .
577: &Suffix($Tournament{'QuestionsNum'}) . ")\n";
578: } else {
579: $qnum = '';
580: }
581: if ($Tournament{'Type'} =~ /Г/) {
582: $imgsrc = "/icons/folder.gif";
583: $alt = "[*]";
584: } else {
585: $imgsrc = "/icons/folder.gif";
586: $alt = "[-]";
587: }
588:
589: if ($SingleTour or $Tournament{'Type'} =~ /Т/) {
590: $list .= dd(img({src=>$imgsrc, alt=>$alt})
1.6 boris 591: . " " . $Tournament{'Title'} . " " .
592: $Tournament{'PlayedAt'} . $qnum) .
1.1 boris 593: dl(
594: dd("["
595: . a({href=>url . "?tour=$Tournament{'Id'}&answer=0"},
596: "вопросы") . "] ["
597: . a({href=>url . "?tour=$Tournament{'Id'}&answer=1"},
598: "вопросы + ответы") . "]")
599: );
600: } else {
601: $list .= dd(a({href=>url . "?tour=$Tournament{'Id'}&comp=1"},
602: img({src=>'/icons/compressed.gif', alt=>'[ZIP]', border=>1}))
603: . " " . img({src=>$imgsrc, alt=>$alt})
604: . " " . a({href=>url . "?tour=$Tournament{'Id'}&answer=0"},
1.6 boris 605: $Tournament{'Title'}. " ".
606: $Tournament{'PlayedAt'}) . $qnum);
1.1 boris 607: }
608: }
609: $output .= dl($list);
610:
611: if ($URL) {
612: $output .=
613: p("Дополнительная информация об этом турнире - по адресу " .
614: a({-'href'=>$URL}, $URL));
615: }
616:
617: if ($Copyright) {
618: $output .= p("Копирайт: " . $Copyright);
619: }
620:
621: if ($Info) {
622: $output .= p($Info);
623: }
624:
625: return $output;
626: }
627:
628: sub Suffix {
629: my ($qnum) = @_;
630: my ($suffix) = 'а' if $qnum =~ /[234]$/;
631: $suffix = '' if $qnum =~ /1$/;
632: $suffix = 'ов' if $qnum =~ /[567890]$/ || $qnum =~ /1.$/;
633: return $suffix;
634: }
635:
636: sub IsTour {
637: my ($dbh, $Id) = @_;
638: my ($sth) = $dbh->prepare("SELECT Type FROM Tournaments
639: WHERE Id=$Id");
640: $sth->execute;
641: return ($sth->fetchrow)[0] =~ /Т/;
642: }
643:
644: # Gets a DB handler (ofcourse) and a tour Id. Prints all the
645: # question of that tour, according to the options.
646: sub PrintTour {
647: my ($dbh, $Id, $answer) = @_;
648: my ($output, $q, $bottom, $field) = ('', 0, '', '');
649:
650: my (%Tour) = &GetTournament($dbh, $Id);
651: my (@Tours) = &GetTours($dbh, $Tour{'ParentId'});
652: my (%Tournament) = &GetTournament($dbh, $Tour{'ParentId'});
653:
654: return 0
655: if ($Tour{'Type'} !~ /Т/);
656:
657: my ($qnum) = $Tour{'QuestionsNum'};
658: my ($suffix) = &Suffix($qnum);
659:
1.4 boris 660: $output .= h2({align=>"center"}, $Tournament{"Title"},
1.6 boris 661: $Tournament{'PlayedAt'},
1.4 boris 662: "<br>", $Tour{"Title"} .
1.1 boris 663: " ($qnum вопрос$suffix)\n") . p;
664:
665: my (@Questions) = &GetTourQuestions($dbh, $Id);
666: for ($q = 0; $q <= $#Questions; $q++) {
667: $output .= &PrintQuestion($dbh, $Questions[$q], $answer, 0);
668: }
669:
670: $output .= hr({-'align'=>'center', -'width'=>'80%'});
671:
672: if ($Tournament{'URL'}) {
673: $output .=
674: p("Дополнительная информация об этом турнире - по адресу " .
675: a({-'href'=>$Tournament{'URL'}}, $Tournament{'URL'}));
676: }
677:
678: if ($Tournament{'Copyright'}) {
679: $output .= p("Копирайт: " . $Tournament{'Copyright'});
680: }
681:
682: if ($Tournament{'Info'}) {
683: $output .= p($Tournament{'Info'});
684: }
685:
686:
687: if ($answer == 0) {
688: $bottom .=
689: "[" . a({href=>url . "?tour=$Id&answer=1"}, "ответы") . "] " . br;
690: }
691: if (&IsTour($dbh, $Id - 1)) {
692: $bottom .=
693: "[" . a({href=>url . "?tour=" . ($Id - 1) . "&answer=0"},
694: "предыдущий тур") . "] ";
695: $bottom .=
696: "[" . a({href=>url . "?tour=" . ($Id - 1) . "&answer=1"},
697: "предыдущий тур с ответами") . "] " . br;
698: }
699: if (&IsTour($dbh, $Id + 1)) {
700: $bottom .=
701: "[" . a({href=>url . "?tour=" . ($Id + 1) . "&answer=0"},
702: "следующий тур") . "] ";
703: $bottom .=
704: "[" . a({href=>url . "?tour=" . ($Id + 1) . "&answer=1"},
705: "следующий тур с ответами") . "] ";
706: }
707:
708: $output .=
709: p({align=>"center"}, font({size=>-1}, $bottom));
710:
711: return $output;
712: }
713:
714: sub PrintField {
715: my ($header, $value, $text) = @_;
716: if ($text) {
1.5 boris 717: $value =~ s/<[\/\w]*>//sg;
718: } else {
719: $value =~ s/^\s+/<br> /mg;
720: $value =~ s/^\|([^\n]*)/<pre>$1<\/pre>/mg;
1.1 boris 721: }
1.29 roma7 722:
1.1 boris 723: return $text ? "$header:\n$value\n\n" :
724: strong("$header: ") . $value . p . "\n";
725: }
726:
727: # Gets a DB handler (ofcourse) and a question Id. Prints
728: # that question, according to the options.
729: sub PrintQuestion {
730: my ($dbh, $Id, $answer, $qnum, $title, $text) = @_;
731: my ($output, $titles) = ('', '');
732:
733: my (%Question) = &GetQuestion($dbh, $Id);
734: if (!$text) {
735: $output .= hr({width=>"50%"});
736: if ($title) {
737: my (%Tour) = GetTournament($dbh, $Question{'ParentId'});
738: my (%Tournament) = GetTournament($dbh, $Tour{'ParentId'});
739: $titles .=
740: dd(img({src=>"/icons/folder.open.gif"}) . " " .
1.6 boris 741: a({href=>url . "?tour=$Tournament{'Id'}"}, $Tournament{'Title'}, $Tournament{'PlayedAt'}));
1.1 boris 742: $titles .=
743: dl(dd(img({src=>"/icons/folder.open.gif"}) . " " .
744: a({href=>url . "?tour=$Tour{'Id'}"}, $Tour{'Title'})));
745: }
746: $output .= dl(strong($titles));
747: }
748:
749: $qnum = $Question{'Number'}
750: if ($qnum == 0);
751:
752: $output .=
753: &PrintField("Вопрос $qnum", $Question{'Question'}, $text);
754:
755: if ($answer) {
756: $output .=
757: &PrintField("Ответ", $Question{'Answer'}, $text);
758:
759: if ($Question{'Authors'}) {
1.29 roma7 760: my $q=$Question{'Authors'};
761:
762: my $sth=$dbh->prepare("select Authors.Id,Name, Surname, Nicks from Authors, A2Q
763: where Authors.Id=Author And Question=$Id");
764: $sth->execute;
765: my ($AuthorId,$Name, $Surname,$other,$Nicks);
766:
767: while ((($AuthorId,$Name, $Surname,$Nicks)=$sth->fetchrow),$AuthorId)
768: {
769: my ($firstletter)=$Name=~m/^./g;
770: # $other.=a({href=>url."?qofauthor=$AuthorId"},"$Name $Surname").". ";
771: my $sha="(?:$Name\\s+$Surname)|(?:$Surname\\s+$Name)|(?:$firstletter\\.\\s*$Surname)|(?:$Surname\\s+$firstletter\\.)|(?:$Surname)|(?:$Name)";
772: $Nicks=~s/^\|//;
773: foreach (split /\|/, $Nicks)
774: {
775: s/ /\\s+/;
776: if (s/>$//) {$sha="$sha|(?:$_)"}
777: else {$sha="(?:$_)|$sha"}
778: }
779: #$output.=br."sha=$sha".br;
780: $q=~s/($sha)/a({href=>url."?qofauthor=$AuthorId"},$1)/ei;
781: }
782:
783: $output .= &PrintField("Автор(ы)", $q, $text);
784:
785: # $output.= &PrintField("Другие вопросы", $other);
1.1 boris 786: }
787:
788: if ($Question{'Sources'}) {
789: $output .= &PrintField("Источник(и)", $Question{'Sources'}, $text);
790: }
791:
792: if ($Question{'Comments'}) {
793: $output .= &PrintField("Комментарии", $Question{'Comments'}, $text);
794: }
795: }
796: return $output;
797: }
798:
799: # Returns the total number of questions currently in the DB.
800: sub GetQNum {
801: my ($dbh) = @_;
802: my ($sth) = $dbh->prepare("SELECT COUNT(*) FROM Questions");
803: $sth->execute;
804: return ($sth->fetchrow)[0];
805: }
1.12 boris 806: sub GetMaxQId {
807: my ($dbh) = @_;
808: my ($sth) = $dbh->prepare("SELECT MAX(QuestionId) FROM Questions");
809: $sth->execute;
810: return ($sth->fetchrow)[0];
811: }
1.1 boris 812:
813: # Returns Id's of 12 random questions
814: sub Get12Random {
815: my ($dbh, $type, $num) = @_;
816: my ($i, @questions, $q, $t, $sth);
1.12 boris 817: my ($qnum) = &GetMaxQId($dbh);
1.1 boris 818: my (%chosen);
819: srand;
820:
1.11 boris 821: for ($i = 0; $i < $num; $i++) {
822: do {
823: $q = int(rand($qnum));
824: $sth = $dbh->prepare("SELECT Type FROM Questions
1.1 boris 825: WHERE QuestionId=$q");
1.11 boris 826: $sth->execute;
827: $t = ($sth->fetchrow)[0];
828: } until !$chosen{$q} && $t && $type =~ /[$t]/;
829: $chosen{$q} = 'y';
830: push @questions, $q;
831: }
832: return @questions;
1.1 boris 833: }
834:
835: sub Include_virtual {
836: my ($fn, $output) = (@_, '');
837:
838: open F , $fn
1.2 boris 839: or return; #die "Can't open the file $fn: $!\n";
1.1 boris 840:
841: while (<F>) {
842: if (/<!--#include/o) {
843: s/<!--#include virtual="\/(.*)" -->/&Include_virtual($1)/e;
844: }
845: if (/<!--#exec/o) {
846: s/<!--#exec.*cmd\s*=\s*"([^"]*)".*-->/`$1`/e;
847: }
848: $output .= $_;
849: }
850: return $output;
851: }
852:
853: sub PrintArchive {
854: my($dbh, $Id) = @_;
855: my ($output, @list, $i);
856:
857: my (%Tournament) = &GetTournament($dbh, $Id);
858: my (@Tours) = &GetTours($dbh, $Id);
859:
860: if ($Tournament{'Type'} =~ /Г/ || $Id == 0) {
861: for ($i = 0; $i <= $#Tours; $i++) {
862: push(@list ,&PrintArchive($dbh, $Tours[$i]));
863: }
864: return @list;
865: }
866: return "$SRCPATH/$Tournament{'FileName'} ";
867: }
868:
869: sub PrintAll {
870: my ($dbh, $Id) = @_;
871: my ($output, $list, $i);
872:
873: my (%Tournament) = &GetTournament($dbh, $Id);
874: my (@Tours) = &GetTours($dbh, $Id);
875: my ($New) = ($Id and $Tournament{'Type'} eq 'Ч' and
876: &NewEnough($Tournament{"CreatedAt"})) ?
877: img({src=>"/znatoki/dimrub/db/new-sml.gif", alt=>"NEW!"}) : "";
878:
879: if ($Id == 0) {
880: $output = h3("Все турниры");
881: } else {
882: $output .= dd(img({src=>"/icons/folder.gif", alt=>"[*]"}) .
883: " " . a({href=>url . "?tour=$Tournament{'Id'}&answer=0"},
1.6 boris 884: $Tournament{'Title'}) ." " . $Tournament{'PlayedAt'} . " $New");
1.1 boris 885: }
886: if ($Id == 0 or $Tournament{'Type'} =~ /Г/) {
887: for ($i = 0; $i <= $#Tours; $i++) {
888: $list .= &PrintAll($dbh, $Tours[$i]);
889: }
890: $output .= dl($list);
891: }
892: return $output;
893: }
894:
895: sub PrintDates {
896: my ($dbh) = @_;
897: my ($from) = param('from_year') . "-" . param('from_month') .
898: "-" . param('from_day');
899: my ($to) = param('to_year') . "-" . param('to_month') . "-" . param('to_day');
900: $from = $dbh->quote($from);
901: $to = $dbh->quote($to);
902: my ($sth) = $dbh->prepare("
903: SELECT DISTINCT Id
904: FROM Tournaments
905: WHERE PlayedAt >= $from AND PlayedAt <= $to
906: AND Type = 'Ч'
907: ");
908: $sth->execute;
909: my (%Tournament, @array, $output, $list);
910:
911: $output = h3("Список турниров, проходивших между $from и $to.");
912: while (@array = $sth->fetchrow) {
913: next
914: if (!$array[0]);
915: %Tournament = &GetTournament($dbh, $array[0]);
916: $list .= dd(img({src=>"/icons/folder.gif", alt=>"[*]"}) .
917: " " . a({href=>url . "?tour=$Tournament{'Id'}&answer=0"},
1.6 boris 918: $Tournament{'Title'}, $Tournament{'PlayedAt'}));
1.1 boris 919: }
920: $output .= dl($list);
921: return $output;
922: }
923:
1.29 roma7 924: sub PrintQOfAuthor
925: {
926: my ($dbh, $id) = @_;
927: $id=$dbh->quote($id);
928: my $sth = $dbh->prepare("SELECT Name, Surname FROM Authors WHERE Id=$id");
929: $sth->execute;
930: my ($name,$surname)=$sth->fetchrow;
931:
932: $sth = $dbh->prepare("SELECT Question FROM A2Q WHERE Author=$id");
933: $sth->execute;
934: my $q;
935: my @Questions;
936: while (($q)=$sth->fetchrow,$q)
937: {push @Questions,$q;}
938:
939: my ($output, $i, $suffix, $hits) = ('', 0, '', $#Questions + 1);
940:
941: if ($hits =~ /1.$/ || $hits =~ /[5-90]$/) {
942: $suffix = 'й';
943: } elsif ($hits =~ /1$/) {
944: $suffix = 'е';
945: } else {
946: $suffix = 'я';
947: }
948:
949: print p({align=>"center"}, "Автор ".strong("$name $surname. ")
950: . " : $hits попадани$suffix.");
951:
952:
953: for ($i = 0; $i <= $#Questions; $i++) {
954: $output = &PrintQuestion($dbh, $Questions[$i], 1, $i + 1, 1);
955: print $output;
956: }
957: }
958:
959:
960: sub PrintAuthors
961: {
962: my ($dbh,$sort)=@_;
963: my($output,$out1,@array,$sth);
964: if ($sort eq 'surname')
965: {
966: $sth =
967: $dbh->prepare("SELECT Id, Name, Surname, QNumber FROM Authors order by Surname");
968:
969: $output.="<TABLE><CAPTION>Алфавитный список авторов</CAPTION>";
970: }
971: else
972: {
973: $sth =
974: $dbh->prepare("SELECT Id, Name, Surname, QNumber FROM Authors Order by QNumber DESC");
975: $output.="<TABLE>";
976: }
977:
978: $sth->execute;
979: $output.=Tr(th["Фамилия, имя", "Количество вопросов"]);
980:
981: $out1='';
982:
983: my $ar=$sth->fetchall_arrayref;
984:
985:
986:
987: foreach my $arr(@$ar)
988: {
989:
990: my ($id,$name,$surname,$kvo)=@$arr;
1.30 roma7 991: if (!$name || !$surname) {#print "Opanki at $id\n"
992: } else
1.29 roma7 993: {
1.31 ! roma7 994: my $add=Tr(td([a({href=>url."?qofauthor=$id"},'[Q] ')."$name $surname", $kvo]))."\n";
1.29 roma7 995: print STDERR $add;
996: $output.=$add;
997: }
998: }
999: $output.="</TABLE>";
1000: return $output;
1001: }
1002:
1003:
1004:
1.1 boris 1005: MAIN:
1006: {
1007: setlocale(LC_CTYPE,'russian');
1008: my($i, $tour);
1009: my($text) = (param('text')) ? 1 : 0;
1010: my($dbh) = DBI->connect("DBI:mysql:chgk", "piataev", "")
1011: or do {
1012: print h1("Временные проблемы") . "База данных временно не
1013: работает. Заходите попозже.";
1014: print &Include_virtual("../dimrub/db/reklama.html");
1015: print end_html;
1016: die "Can't connect to DB chgk\n";
1017: };
1.11 boris 1018: if (!param('comp') and !param('sqldump') and !$text) {
1.1 boris 1019: print header;
1020: print start_html(-"title"=>'Database of the questions',
1021: -author=>'dimrub@icomverse.com',
1022: -bgcolor=>'#fff0e0',
1023: -vlink=>'#800020');
1024: print &Include_virtual("../dimrub/db/reklama.html");
1025: }
1.22 roma7 1026:
1027: if ($^O =~ /win/i) {
1028: $thislocale = "Russian_Russia.20866";
1029: } else {
1030: $thislocale = "ru_RU.KOI8-R";
1031: }
1032: POSIX::setlocale( &POSIX::LC_ALL, $thislocale );
1033:
1034: if ((uc 'а') ne 'А') {print "Koi8-r locale not installed!\n"};
1035:
1.1 boris 1036:
1037: if ($text) {
1038: print header('text/plain');
1039: }
1040:
1041: if (param('rand')) {
1.7 boris 1042: my ($type, $qnum) = ('', 12);
1043: $type .= 'Б' if (param('brain'));
1044: $type .= 'Ч' if (param('chgk'));
1.1 boris 1045: $qnum = param('qnum') if (param('qnum') =~ /^\d+$/);
1.7 boris 1046: $qnum = 0 if (!$type);
1.1 boris 1047: if (param('email') && -x $SENDMAIL &&
1048: open(F, "| $SENDMAIL -t -n")) {
1049: my ($Email) = param('email');
1050: my ($mime_type) = $text ? "plain" : "html";
1051: print F <<EOT;
1052: To: $Email
1.8 boris 1053: From: olegstemanov\@mail.ru
1.1 boris 1054: Subject: Sluchajnij Paket Voprosov "Chto? Gde? Kogda?"
1055: MIME-Version: 1.0
1056: Content-type: text/$mime_type; charset="koi8-r"
1057:
1058: EOT
1059: print F &PrintRandom($dbh, $type, $qnum, $text);
1060: close F;
1061: print "Пакет случайно выбранных вопросов послан. Нажмите
1062: на <B>Reload</B> для получения еще одного пакета";
1063: } else {
1064: print &PrintRandom($dbh, $type, $qnum, $text);
1065: }
1.29 roma7 1066: }
1067: elsif (param('authors')){
1068: print &PrintAuthors($dbh,param('authors'));
1069: }
1070: elsif (param('qofauthor')){
1071: &PrintQOfAuthor($dbh,param('qofauthor'));
1072: }
1073: elsif (param('sstr')) {
1.14 roma7 1074: &PrintSearch($dbh, param('sstr'), param('metod'));
1.1 boris 1075: } elsif (param('all')) {
1076: print &PrintAll($dbh, 0);
1077: } elsif (param('from_year') && param('to_year')) {
1078: print &PrintDates($dbh);
1079: } elsif (param('comp')) {
1.9 boris 1080: print header(
1081: -'Content-Type' => 'application/x-zip-compressed; name="db.zip"',
1082: -'Content-Disposition' => 'attachment; filename="db.zip"'
1083: );
1084: $tour = (param('tour')) ? param('tour') : 0;
1085: my (@files) = &PrintArchive($dbh, $tour);
1086: open F, "$ZIP -j - $SRCPATH/COPYRIGHT @files |";
1087: print (<F>);
1088: close F;
1089: $dbh->disconnect;
1090: exit;
1091: } elsif (param('sqldump')) {
1092: print header(
1093: -'Content-Type' => 'application/x-zip-compressed; name="dump.zip"',
1094: -'Content-Disposition' => 'attachment; filename="dump.zip"'
1095: );
1.10 boris 1096: open F, "$ZIP -j - $DUMPFILE |";
1.9 boris 1097: print (<F>);
1098: close F;
1099: $dbh->disconnect;
1100: exit;
1101:
1.1 boris 1102: } else {
1103: $tour = (param('tour')) ? param('tour') : 0;
1104: if ($tour !~ /^[0-9]*$/) {
1105: my ($sth) = $dbh->prepare("SELECT Id FROM Tournaments
1106: WHERE FileName = '$tour.txt'");
1107: $sth->execute;
1108: $tour = ($sth->fetchrow)[0];
1109: }
1110: print &PrintTournament($dbh, $tour, param('answer'));
1111: }
1112: if (!$text) {
1113: print &Include_virtual("../dimrub/db/footer.html");
1114: print end_html;
1115: }
1116: $dbh->disconnect;
1117: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>