/[suikacvs]/test/suika-accounts/edit.cgi
Suika

Contents of /test/suika-accounts/edit.cgi

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.2 - (hide annotations) (download)
Wed Oct 29 16:27:15 2008 UTC (15 years, 6 months ago) by wakaba
Branch: MAIN
Changes since 1.1: +200 -46 lines
Properties

1 wakaba 1.1 #!/usr/bin/perl
2     use strict;
3    
4     use lib qw[/home/httpd/html/www/markup/html/whatpm
5     /home/wakaba/work/manakai2/lib];
6    
7     use CGI::Carp qw[fatalsToBrowser];
8     require Message::CGI::Carp;
9    
10     require 'users.pl';
11    
12     require Message::CGI::HTTP;
13     require Encode;
14     my $cgi = Message::CGI::HTTP->new;
15     $cgi->{decoder}->{'#default'} = sub {
16     return Encode::decode ('utf-8', $_[1]);
17     };
18    
19     require Message::DOM::DOMImplementation;
20     my $dom = Message::DOM::DOMImplementation->new;
21    
22     my $path = $cgi->path_info;
23     $path = '' unless defined $path;
24    
25     my @path = split m#/#, percent_decode ($path), -1;
26     shift @path;
27    
28     if (@path == 3 and
29     $path[0] eq 'users' and
30     $path[1] =~ /\A[0-9a-z-]+\z/) {
31     my $user_id = $path[1];
32 wakaba 1.2 my $ac = check_access_right (allowed_users => {$user_id => 1},
33     allowed_groups => {'admin-users' => 1});
34 wakaba 1.1
35     if ($path[2] eq '') {
36     my $user_prop = get_user_prop ($user_id);
37     if ($user_prop) {
38     binmode STDOUT, ':encoding(utf-8)';
39    
40     my $e_user_id = htescape ($user_id);
41    
42     print qq[Content-Type: text/html; charset=utf-8
43    
44     <!DOCTYPE HTML>
45     <html lang=en>
46     <title>User $e_user_id</title>
47     <link rel=stylesheet href="/www/style/html/xhtml">
48     <h1>User $e_user_id</h1>
49     ];
50    
51     my @joined;
52     my @requested;
53     my @invited;
54     my @can_join;
55     my @can_request;
56     for my $group_id (get_all_groups ()) {
57     my $gs = $user_prop->{'group.' . $group_id};
58     if ($gs->{member}) {
59     push @joined, $group_id;
60     } elsif ($gs->{no_approval}) {
61     push @requested, $group_id;
62     } elsif ($gs->{invited}) {
63     push @invited, $group_id;
64     } else {
65     my $group_prop = get_group_prop ($group_id);
66     if ($group_prop->{join_condition}->{invitation}) {
67     #
68     } elsif ($group_prop->{join_condition}->{approval}) {
69     push @can_request, $group_id;
70     } else {
71     push @can_join, $group_id;
72     }
73     }
74     }
75    
76     print qq[<section id=groups><h2>Groups</h2>];
77    
78     if (@joined) {
79     print_list_section
80     (id => 'groups-joined',
81     title => 'Groups you have joined',
82     items => \@joined,
83     print_item => sub {
84     my $group_id = shift;
85     print q[<form action="group.] . htescape ($group_id);
86     print q[" accept-charset=utf-8 method=post>];
87     print q[<a href="../../groups/].htescape ($group_id) . '/';
88     print q[">] . htescape ($group_id), q[</a> ];
89     print q[<input type=hidden name=action value=leave>];
90     print q[<input type=submit value="Leave this group"></form>];
91     });
92     }
93    
94     if (@requested) {
95     print_list_section
96     (id => 'groups-requested',
97     title => 'Groups you have requested to join but not approved yet',
98     items => \@requested,
99     print_item => sub {
100     my $group_id = shift;
101     print q[<form action="group.] . htescape ($group_id);
102     print q[" accept-charset=utf-8 method=post>];
103     print q[<a href="../../groups/].htescape ($group_id) . '/';
104     print q[">] . htescape ($group_id), q[</a> ];
105     print q[<input type=hidden name=action value=leave>];
106     print q[<input type=submit value="Cancel the request"></form>];
107     });
108     }
109    
110     if (@invited) {
111     print_list_section
112     (id => 'groups-invited',
113     title => 'Groups you have been invited but not joined yet, or you have left',
114     items => \@invited,
115     print_item => sub {
116     my $group_id = shift;
117     print q[<form action="group.] . htescape ($group_id);
118     print q[" accept-charset=utf-8 method=post>];
119     print q[<a href="../../groups/].htescape ($group_id) . '/';
120     print q[">] . htescape ($group_id), q[</a> ];
121     print q[<input type=hidden name=action value=join>];
122     print q[<input type=submit value="Join this group"></form>];
123     });
124     }
125    
126     if (@can_join) {
127     print_list_section
128     (id => 'groups-can-join',
129     title => 'Groups you can join now (without approval)',
130     items => \@can_join,
131     print_item => sub {
132     my $group_id = shift;
133     print q[<form action="group.] . htescape ($group_id);
134     print q[" accept-charset=utf-8 method=post>];
135     print q[<a href="../../groups/].htescape ($group_id) . '/';
136     print q[">] . htescape ($group_id), q[</a>];
137     print q[<input type=hidden name=action value=join>];
138     print q[<input type=submit value="Join this group"></form>];
139     });
140     }
141    
142     if (@can_request) {
143     print_list_section
144     (id => 'groups-can-request',
145     title => 'Groups you can request to join (approval required to join)',
146     items => \@can_request,
147     print_item => sub {
148     my $group_id = shift;
149     print q[<form action="group.] . htescape ($group_id);
150     print q[" accept-charset=utf-8 method=post>];
151     print q[<a href="../../groups/].htescape ($group_id) . '/';
152     print q[">] . htescape ($group_id), q[</a> ];
153     print q[<input type=hidden name=action value=join>];
154     print q[<input type=submit value="Join this group"></form>];
155     });
156     }
157    
158 wakaba 1.2 print q[</section><section id=props><h2>Properties</h2>
159    
160     <p><em>Though these properties are only accessible to administrators,
161     you are advised not to expose any confidential data.</em>];
162    
163     print_prop_list ($ac, $user_prop,
164     {
165     name => 'full_name',
166     label => 'Full name',
167     field_type => 'text',
168     },
169     {
170     name => 'mail_addr',
171     label => 'Mail address',
172     field_type => 'email',
173     },
174     {
175     name => 'home_url',
176     label => 'Web site URL',
177     field_type => 'url',
178     },
179     );
180 wakaba 1.1
181 wakaba 1.2 print qq[</section><section id=password>
182 wakaba 1.1 <h2>Password</h2>
183    
184     <form action=password method=post accept-charset=utf-8>
185    
186     <p>You can change the password.
187    
188     <p><strong>New password</strong>: <input type=password name=user-pass
189     size=10 required pattern=".{4,}" title="Type 4 characters at minimum">
190    
191     <p><strong>New password</strong> (type again): <input type=password
192     name=user-pass2 size=10 required pattern=".{4,}">
193    
194     <p><input type=submit value=Change>
195    
196     </form>
197     </section>
198    
199     <section id=disable-account><h2>Disable account</h2>
200    
201     <form action=disabled method=post accept-charset=utf-8>
202    
203     <p><label><input type=checkbox name=action value=enable
204     @{[$user_prop->{disabled} ? '' : 'checked']}> Enable this
205     account.</label>
206    
207     <p><strong>Caution!</strong> Once you disable your own account, you
208     cannot enable your account by yourself.
209    
210     <p><input type=submit value=Change>
211    
212     </form>
213    
214     </section>];
215    
216     exit;
217     }
218     } elsif ($path[2] =~ /\Agroup\.([0-9a-z-]+)\z/) {
219     my $group_id = $1;
220     if ($cgi->request_method eq 'POST') {
221     lock_start ();
222     binmode STDOUT, ':encoding(utf-8)';
223    
224     my $user_prop = get_user_prop ($user_id);
225     my $group_prop = get_group_prop ($group_id);
226    
227     if ($user_prop and $group_prop) {
228     my $gs = ($user_prop->{'group.' . $group_id} ||= {});
229    
230     my $action = $cgi->get_parameter ('action');
231     my $status;
232     if ($action eq 'join') {
233 wakaba 1.2 if (scalar $cgi->get_parameter ('agreed')) {
234     if ($gs->{member}) {
235     $status = q[You are a member];
236     #
237     } elsif ($gs->{no_approval}) {
238     $status = q[You are waiting for an approval];
239 wakaba 1.1 #
240 wakaba 1.2 } elsif ($gs->{invited}) {
241 wakaba 1.1 $gs->{member} = 1;
242     $status = q[Registered];
243     #
244 wakaba 1.2 } else {
245     if ($group_prop->{join_condition}->{invitation}) {
246     print_error (403, 'You are not invited to this group');
247     exit;
248     } elsif ($group_prop->{join_condition}->{approval}) {
249     $gs->{no_approval} = 1;
250     $status = q[Request submitted];
251     #
252     } else {
253     $gs->{member} = 1;
254     $status = q[Registered];
255     #
256     }
257 wakaba 1.1 }
258 wakaba 1.2 } else {
259     my $e_group_id = htescape ($group_id);
260     print qq[Content-Type: text/html; charset=utf-8
261    
262     <!DOCTYPE HTML>
263     <html lang=en>
264     <title>Joining the group $e_group_id</title>
265     <link rel=stylesheet href="/www/style/html/xhtml">
266     <h1>Joining the group $e_group_id</h1>
267    
268     <dl>
269     <dt>Description
270     <dd>@{[$group_prop->{desc}]}
271     </dl>
272    
273     <form action="@{[htescape ($cgi->request_uri)]}" accept-charset=utf-8 method=post>
274     <input type=hidden name=action value=join>
275    
276     <p>Do you really want to join this group?
277     <input type=submit name=agreed value=yes>
278     <input type=button value=no onclick="history.back ()">
279    
280     </form>];
281     exit;
282 wakaba 1.1 }
283     } elsif ($action eq 'leave') {
284     if ($gs->{member}) {
285     delete $gs->{member};
286     $gs->{invited} = 1;
287     $status = 'Unregistered';
288     #
289     } elsif ($gs->{no_approval}) {
290     delete $gs->{no_approval};
291     delete $gs->{invited};
292     $status = 'Request canceled';
293     #
294     } else {
295     $status = 'You are not a member';
296     #
297     }
298     } else {
299     print_error (400, 'Bad action parameter');
300     exit;
301     }
302    
303     set_user_prop ($user_id, $user_prop);
304     regenerate_htpasswd_and_htgroup ();
305     commit ();
306    
307 wakaba 1.2 redirect (303, $status, './');
308 wakaba 1.1 exit;
309     }
310     }
311     } elsif ($path[2] eq 'password') {
312     if ($cgi->request_method eq 'POST') {
313     lock_start ();
314     binmode STDOUT, ':encoding(utf-8)';
315    
316     my $user_prop = get_user_prop ($user_id);
317    
318     if ($user_prop) {
319     $user_prop->{pass_crypted} = check_password ($cgi);
320    
321     set_user_prop ($user_id, $user_prop);
322     regenerate_htpasswd_and_htgroup ();
323     commit ();
324    
325     ## Browsers do not support 205.
326     #print qq[Status: 205 Password changed\n\n];
327     print qq[Status: 204 Password changed\n\n];
328     exit;
329     }
330     }
331     } elsif ($path[2] eq 'disabled') {
332     if ($cgi->request_method eq 'POST') {
333     lock_start ();
334     binmode STDOUT, ':encoding(utf-8)';
335    
336     my $user_prop = get_user_prop ($user_id);
337    
338     if ($user_prop) {
339     my $action = $cgi->get_parameter ('action');
340     if (defined $action and $action eq 'enable') {
341     delete $user_prop->{disabled};
342     } else {
343     $user_prop->{disabled} = 1;
344     }
345    
346     set_user_prop ($user_id, $user_prop);
347     regenerate_htpasswd_and_htgroup ();
348     commit ();
349    
350     print "Status: 204 Property updated\n\n";
351     exit;
352     }
353     }
354 wakaba 1.2 } elsif ($path[2] eq 'prop') {
355     if ($cgi->request_method eq 'POST') {
356     lock_start ();
357     my $user_prop = get_user_prop ($user_id);
358     if ($user_prop) {
359     binmode STDOUT, ':encoding(utf-8)';
360    
361     my $prop_name = $cgi->get_parameter ('name');
362     if (defined $prop_name and
363     {
364     full_name => 1,
365     mail_addr => 1,
366     home_url => 1,
367     }->{$prop_name}) {
368     $user_prop->{$prop_name} = $cgi->get_parameter ('value');
369    
370     set_user_prop ($user_id, $user_prop);
371     commit ();
372    
373     print "Status: 204 Property updated\n\n";
374     exit;
375     } else {
376     print_error (400, 'Bad property');
377     exit;
378     }
379     }
380     }
381 wakaba 1.1 }
382     } elsif (@path == 3 and
383     $path[0] eq 'groups' and
384     $path[1] =~ /\A[0-9a-z-]+\z/) {
385     my $group_id = $path[1];
386     my $ac = check_access_right (allowed_groups => {'admin-groups' => 1},
387     group_context => $group_id);
388    
389     if ($path[2] eq '') {
390     my $group_prop = get_group_prop ($group_id);
391     if ($group_prop) {
392     binmode STDOUT, ':encoding(utf-8)';
393    
394     my $e_group_id = htescape ($group_id);
395    
396     print qq[Content-Type: text/html; charset=utf-8
397    
398     <!DOCTYPE HTML>
399     <html lang=en>
400     <title>Group $e_group_id</title>
401     <link rel=stylesheet href="/www/style/html/xhtml">
402 wakaba 1.2 <h1>Group $e_group_id</h1>];
403    
404     print q[<section id=props><h2>Properties</h2>];
405    
406     print_prop_list ($ac, $group_prop,
407     {
408     name => 'desc',
409     label => 'Description',
410     field_type => 'textarea',
411     public => 1,
412     },
413     {
414     name => 'admin_group',
415     label => 'Administrative group',
416     field_type => 'text',
417     },
418     );
419    
420     print q[</section><section id=members><h2>Members</h2>];
421 wakaba 1.1
422     if ($ac->{read_group_member_list}) {
423     my @members;
424     my @apps;
425     my @invited;
426     for my $user_id (get_all_users ()) {
427     my $user_prop = get_user_prop ($user_id);
428     my $gs = $user_prop->{'group.' . $group_id};
429     if ($gs->{member}) {
430     push @members, $user_id;
431     } elsif ($gs->{no_approval}) {
432     push @apps, $user_id;
433     } elsif ($gs->{invited}) {
434     push @invited, $user_id;
435     }
436     }
437    
438     if (@members) {
439     print_list_section
440     (id => 'formal-members',
441     title => 'Formal members',
442     items => \@members,
443     print_item => sub {
444     my $user_id = shift;
445     print q[<form action="user.] . htescape ($user_id);
446     print q[" accept-charset=utf-8 method=post>];
447     print qq[<a href="../../users/@{[htescape ($user_id)]}/">];
448     print '' . htescape ($user_id) . q[</a> ];
449     print q[<input type=hidden name=action value=unapprove>];
450     print q[<input type=submit value="Kick"></form>];
451     });
452     }
453    
454     if (@apps) {
455     print_list_section
456     (id => 'non-approved-users',
457     title => 'Users who are waiting for the approval to join',
458     items => \@apps,
459     print_item => sub {
460     my $user_id = shift;
461     print q[<form action="user.] . htescape ($user_id);
462     print q[" accept-charset=utf-8 method=post>];
463     print qq[<a href="../../users/@{[htescape ($user_id)]}/">];
464     print '' . htescape ($user_id) . q[</a> ];
465     print q[<input type=hidden name=action value=approve>];
466     print q[<input type=submit value=Approve></form>];
467     });
468     }
469    
470     if (@invited) {
471     print_list_section
472     (id => 'invited-users',
473     title => 'Users who are invited but not joined or are leaved',
474     items => \@invited,
475     print_item => sub {
476     my $user_id = shift;
477     print q[<form action="user.] . htescape ($user_id);
478     print q[" accept-charset=utf-8 method=post>];
479     print qq[<a href="../../users/@{[htescape ($user_id)]}/">];
480     print '' . htescape ($user_id), q[</a> ];
481     print q[<input type=hidden name=action value=unapprove>];
482     print q[<input type=submit value="Cancel invitation"></form>];
483     });
484     }
485     }
486    
487     my $join_condition = $group_prop->{join_condition};
488     my $disabled = $ac->{write} ? '' : 'disabled';
489     print qq[<section id=member-approval>
490     <h3>Member approval policy</h3>
491    
492     <form action=join-condition method=post accept-charset=utf-8>
493    
494     <p><label><input type=radio name=condition value=invitation $disabled
495     @{[$join_condition->{invitation} ? 'checked' : '']}> A user who is
496     invited by an administrator of the group can join the group.</label>
497    
498     <p><label><input type=radio name=condition value=approval $disabled
499     @{[(not $join_condition->{invitation} and $join_condition->{approval})
500     ? 'checked' : '']}> A user who is invited or approved by an
501     administrator of the group can join the group.</label>
502    
503     <p><label><input type=radio name=condition value=anyone $disabled
504     @{[(not $join_condition->{invitation} and not
505     $join_condition->{approval}) ? 'checked' : '']}> Any user can join
506     the group.</label>
507    
508     @{[$disabled ? '' : '<p><input type=submit value=Change>']}
509    
510     </form>
511    
512     </section>];
513    
514     if ($ac->{write}) {
515     print q[<section id=member-invitation>
516     <h3>Invite a user</h3>
517    
518     <form action=invite-user accept-charset=utf-8 method=post>
519    
520     <p><strong>User id</strong>: <input type=text name=user-id
521     maxlength=20 size=10 required pattern="[0-9a-z-]{4,20}">
522    
523     <p><input type=submit value=Invite>
524    
525     </form>
526    
527     </section>];
528     }
529    
530     print q[</section>];
531    
532     exit;
533     }
534     } elsif ($path[2] eq 'join-condition') {
535     forbidden () unless $ac->{write};
536    
537     if ($cgi->request_method eq 'POST') {
538     lock_start ();
539     my $group_prop = get_group_prop ($group_id);
540     if ($group_prop) {
541     binmode STDOUT, ':encoding(utf-8)';
542    
543     my $new_condition = $cgi->get_parameter ('condition');
544     if ($new_condition eq 'invitation') {
545     $group_prop->{join_condition}->{invitation} = 1;
546     $group_prop->{join_condition}->{approval} = 1;
547     } elsif ($new_condition eq 'approval') {
548     $group_prop->{join_condition}->{approval} = 1;
549     delete $group_prop->{join_condition}->{invitation};
550     } else {
551     delete $group_prop->{join_condition}->{invitation};
552     delete $group_prop->{join_condition}->{approval};
553     }
554    
555     set_group_prop ($group_id, $group_prop);
556     commit ();
557    
558     print "Status: 204 join-condition property updated\n\n";
559     exit;
560     }
561     }
562 wakaba 1.2 } elsif ($path[2] eq 'prop') {
563     forbidden () unless $ac->{write};
564    
565     if ($cgi->request_method eq 'POST') {
566     lock_start ();
567     my $group_prop = get_group_prop ($group_id);
568     if ($group_prop) {
569     binmode STDOUT, ':encoding(utf-8)';
570    
571     my $prop_name = $cgi->get_parameter ('name');
572     if (defined $prop_name and
573     {desc => 1, admin_group => 1}->{$prop_name}) {
574     $group_prop->{$prop_name} = $cgi->get_parameter ('value');
575    
576     set_group_prop ($group_id, $group_prop);
577     commit ();
578    
579     print "Status: 204 Property updated\n\n";
580     exit;
581     } else {
582     print_error (400, 'Bad property');
583     exit;
584     }
585     }
586     }
587 wakaba 1.1 } elsif ($path[2] =~ /\Auser\.([0-9a-z-]+)\z/ or
588     $path[2] eq 'invite-user') {
589     my $user_id = $1 // $cgi->get_parameter ('user-id') // '';
590     if ($user_id =~ /\A[0-9a-z-]+\z/ and
591     $cgi->request_method eq 'POST') {
592     forbidden () unless $ac->{write};
593    
594     lock_start ();
595     my $group_prop = get_group_prop ($group_id);
596     my $user_prop = get_user_prop ($user_id);
597     if ($group_prop and $user_prop) {
598     binmode STDOUT, ':encoding(utf-8)';
599    
600     my $gs = ($user_prop->{'group.' . $group_id} ||= {});
601    
602     my $action = $cgi->get_parameter ('action');
603     $action = 'approve' if $path[2] eq 'invite-user';
604     my $status;
605     if ($action eq 'approve') {
606     if ($gs->{member}) {
607     $status = 'He is a member';
608     #
609     } elsif ($gs->{no_approval}) {
610     $gs->{member} = 1;
611     delete $gs->{no_approval};
612     $status = 'Registered';
613     #
614     } elsif ($gs->{invited}) {
615     $status = 'He has been invited';
616     #
617     } else {
618     $gs->{invited} = 1;
619     $status = 'Invited';
620     #
621     }
622     } elsif ($action eq 'unapprove') {
623     if ($gs->{member}) {
624     delete $gs->{member};
625     delete $gs->{invited};
626     $status = 'Unregistered';
627     #
628     } elsif ($gs->{invited}) {
629     delete $gs->{invited};
630     $status = 'Invitation canceled';
631     #
632     } else {
633     $status = 'Not a member';
634     #
635     }
636     } else {
637     print_error (400, 'Bad action parameter');
638     exit;
639     }
640    
641     set_user_prop ($user_id, $user_prop);
642     regenerate_htpasswd_and_htgroup ();
643     commit ();
644    
645     print "Status: 204 $status\n\n";
646     exit;
647     }
648     }
649     }
650     } elsif (@path == 1 and $path[0] eq 'new-group') {
651     check_access_right (allowed_groups => {'admin-groups' => 1});
652    
653     if ($cgi->request_method eq 'POST') {
654     lock_start ();
655     binmode STDOUT, ':encoding(utf-8)';
656    
657     my $group_id = $cgi->get_parameter ('group-id');
658    
659     if ($group_id !~ /\A[0-9a-z-]{4,20}\z/) {
660     print_error (400, qq[Group id "$group_id" is invalid; use characters [0-9a-z-]{4,20}]);
661     exit;
662     }
663    
664     if (get_group_prop ($group_id)) {
665     print_error (400, qq[Group id "$group_id" is already used]);
666     exit;
667     }
668    
669     my $group_prop = {id => $group_id};
670     set_group_prop ($group_id, $group_prop);
671    
672     commit ();
673    
674     my $group_url = get_absolute_url ('groups/' . $group_id . '/');
675    
676     print qq[Status: 201 Group registered
677     Location: $group_url
678     Content-Type: text/html; charset=utf-8
679    
680     <!DOCTYPE HTML>
681     <html lang=en>
682     <title>Group "@{[htescape ($group_id)]}" registered</title>
683     <link rel=stylesheet href="/www/style/html/xhtml">
684     <h1>Group "@{[htescape ($group_id)]}" registered</h1>
685     <p>The new group is created successfully.
686     <p>See <a href="@{[htescape ($group_url)]}">the group information page</a>.];
687     exit;
688     } else {
689     binmode STDOUT, ":encoding(utf-8)";
690     print qq[Content-Type: text/html; charset=utf-8
691    
692     <!DOCTYPE HTML>
693     <html lang=en>
694     <title>Create a new group</title>
695     <link rel=stylesheet href="/www/style/html/xhtml">
696     <h1>Create a new group</h1>
697    
698     <form action=new-group accept-charset=utf-8 method=post>
699    
700     <p><strong>Group id</strong>: <input type=text name=group-id
701     maxlength=20 size=10 required pattern="[0-9a-z-]{4,20}"
702     title="Use a string of characters 'a'..'z', '0'..'9', and '-' with length 4..10 (inclusive)">
703    
704     <p><input type=submit value=Create>
705    
706     </form>];
707     exit;
708     }
709     } elsif (@path == 1 and $path[0] eq '') {
710     my $user_id = $cgi->remote_user;
711     forbidden () if not defined $user_id or $user_id !~ /\A[0-9a-z-]+\z/;
712    
713 wakaba 1.2 redirect (303, 'See other', 'users/' . $user_id . '/');
714 wakaba 1.1 exit;
715     } elsif (@path == 0) {
716 wakaba 1.2 redirect (301, 'Moved', 'edit/');
717 wakaba 1.1 exit;
718     }
719    
720     print_error (404, 'Not found');
721     exit;
722    
723     sub print_list_section (%) {
724     my %opt = @_;
725     $opt{level} ||= 3;
726    
727     print q[<section id="] . htescape ($opt{id});
728     print q["><h] . $opt{level} . q[>] . htescape ($opt{title});
729     print q[</h] . $opt{level} . q[><ul>];
730     for my $item (sort {$a cmp $b} @{$opt{items}}) {
731     print q[<li>];
732     $opt{print_item}->($item);
733     }
734     print q[</ul></section>];
735     } # print_list_section
736    
737 wakaba 1.2 sub print_prop_list ($$@) {
738     my $ac = shift;
739     my $prop_hash = shift;
740    
741     for my $prop (@_) {
742     if ($prop->{public}) {
743     print q[<p><strong>], htescape ($prop->{label}), q[</strong>: ];
744     print $prop_hash->{$prop->{name}};
745     }
746    
747     if ($ac->{write}) {
748     print q[<form action="prop" accept-charset=utf-8 method=post>];
749     print q[<input type=hidden name=name value="], htescape ($prop->{name}), q[">];
750     if ($prop->{field_type} eq 'textarea') {
751     print q[<p><label><strong>], htescape ($prop->{label});
752     print q[</strong>: <br><textarea name="value"];
753     print q[>], htescape ($prop_hash->{$prop->{name}} // '');
754     print q[</textarea></label>];
755     print q[<p><input type=submit value=Save>];
756     } else {
757     print q[<p><label><strong>], htescape ($prop->{label});
758     print q[</strong>: <input type="] . $prop->{field_type};
759     print q[" name="value" ];
760     print q[value="], htescape ($prop_hash->{$prop->{name}} // '');
761     print q["></label> ];
762     print q[<input type=submit value=Save>];
763     }
764     print q[</form>];
765     }
766     }
767     } # print_prop_list
768    
769 wakaba 1.1 sub check_access_right (%) {
770     my %opt = @_;
771    
772     my $user_id = $cgi->remote_user;
773     forbidden () if not defined $user_id or $user_id !~ /\A[0-9a-z-]+\z/;
774    
775     my $user_prop = get_user_prop ($user_id);
776     forbidden () unless $user_prop;
777    
778 wakaba 1.2 my $ac = {};
779     my $return_ac;
780    
781 wakaba 1.1 if ($opt{allowed_users}->{$user_id}) {
782 wakaba 1.2 $ac->{write} = 1;
783     $return_ac = 1;
784 wakaba 1.1 }
785    
786     for my $group_id (keys %{$opt{allowed_groups} or {}}) {
787     my $group_prop = get_group_prop ($group_id);
788     next unless $group_prop;
789    
790     my $gs = $user_prop->{'group.' . $group_id};
791     if ($gs->{member}) {
792     return {write => 1, read_group_member_list => 1};
793     }
794     }
795    
796     if (defined $opt{group_context}) {
797     my $group_prop = get_group_prop ($opt{group_context});
798     if ($group_prop) {
799 wakaba 1.2 if (defined $group_prop->{admin_group}) {
800     my $ag_prop = get_group_prop ($group_prop->{admin_group});
801     if ($ag_prop and
802     $user_prop->{'group.' . $group_prop->{admin_group}}->{member}) {
803     return {write => 1, read_group_member_list => 1};
804     }
805     }
806    
807 wakaba 1.1 my $gs = $user_prop->{'group.' . $opt{group_context}};
808     if ($gs->{member}) {
809     $return_ac = 1;
810     } elsif ($gs->{invited}) {
811     $return_ac = 1;
812     } elsif ($group_prop->{join_condition}->{acception}) {
813     $return_ac = 1;
814     } elsif (not $group_prop->{join_condition}->{invitation}) {
815     $return_ac = 1;
816     }
817     }
818     }
819    
820     return $ac if $return_ac;
821    
822     forbidden ();
823     } # check_access_right
824    
825     sub forbidden () {
826     my $user = $cgi->remote_user;
827     if (defined $user) {
828     print_error (403, q[Forbidden (you've logged in as ] . $user . ')');
829     } else {
830     print_error (403, 'Forbidden');
831     }
832     exit;
833     } # forbidden
834 wakaba 1.2
835     sub redirect ($$$) {
836     my ($code, $status, $url) = @_;
837    
838     my $abs_url = get_absolute_url ($url);
839    
840     print qq[Status: $code $status
841     Location: $abs_url
842     Content-Type: text/html; charset=us-ascii
843    
844     See <a href="@{[htescape ($abs_url)]}">other page</a>.];
845     } # redirect
846 wakaba 1.1
847     sub percent_decode ($) {
848     return $dom->create_uri_reference ($_[0])
849     ->get_iri_reference
850     ->uri_reference;
851     } # percent_decode
852    
853     sub get_absolute_url ($) {
854     return $dom->create_uri_reference ($_[0])
855     ->get_absolute_reference ($cgi->request_uri)
856     ->get_iri_reference
857     ->uri_reference;
858     } # get_absolute_url

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24