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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.3 - (hide annotations) (download)
Thu Oct 30 11:57:07 2008 UTC (16 years, 1 month ago) by wakaba
Branch: MAIN
Changes since 1.2: +185 -99 lines
Pseudo-I18N; Japanese language catalog added

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

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24