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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.4 - (hide annotations) (download)
Thu Oct 30 12:05:49 2008 UTC (15 years, 6 months ago) by wakaba
Branch: MAIN
Changes since 1.3: +4 -3 lines
Use redirect after changing member status

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 wakaba 1.4 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.4 redirect (303, $status, './#groups');
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 wakaba 1.4 #print "Status: 204 $status\n\n";
707     redirect (303, $status, './#members');
708 wakaba 1.1 exit;
709     }
710     }
711     }
712     } elsif (@path == 1 and $path[0] eq 'new-group') {
713     check_access_right (allowed_groups => {'admin-groups' => 1});
714    
715     if ($cgi->request_method eq 'POST') {
716     lock_start ();
717     binmode STDOUT, ':encoding(utf-8)';
718    
719     my $group_id = $cgi->get_parameter ('group-id');
720    
721     if ($group_id !~ /\A[0-9a-z-]{4,20}\z/) {
722 wakaba 1.3 print_error (400,
723     q[Group id %s is invalid; use characters [0-9a-z-]{4,20}],
724     $group_id);
725 wakaba 1.1 exit;
726     }
727    
728     if (get_group_prop ($group_id)) {
729 wakaba 1.3 print_error (400, q[Group id %s is already used], $group_id);
730 wakaba 1.1 exit;
731     }
732    
733     my $group_prop = {id => $group_id};
734     set_group_prop ($group_id, $group_prop);
735    
736     commit ();
737    
738     my $group_url = get_absolute_url ('groups/' . $group_id . '/');
739    
740     print qq[Status: 201 Group registered
741     Location: $group_url
742     Content-Type: text/html; charset=utf-8
743    
744     <!DOCTYPE HTML>
745     <html lang=en>
746 wakaba 1.3 <title>];
747     print_text ('Group %s registered', sub { print '', htescape ($group_id) });
748     print q[</title>
749 wakaba 1.1 <link rel=stylesheet href="/www/style/html/xhtml">
750 wakaba 1.3 <h1>];
751     print_text ('Group %s registered', sub { print '', htescape ($group_id) });
752     print q[</h1><p>];
753     print_text ('The new group is created successfully.');
754     print q[<p>];
755     print_text ('See %s.', sub {
756     print qq[<a href="@{[htescape ($group_url)]}">];
757     print_text ('the group information page');
758     print qq[</a>];
759     });
760 wakaba 1.1 exit;
761     } else {
762     binmode STDOUT, ":encoding(utf-8)";
763 wakaba 1.3 print q[Content-Type: text/html; charset=utf-8
764 wakaba 1.1
765     <!DOCTYPE HTML>
766     <html lang=en>
767 wakaba 1.3 <title>];
768     print_text ('Create a new group');
769     print q[</title>
770 wakaba 1.1 <link rel=stylesheet href="/www/style/html/xhtml">
771 wakaba 1.3 <h1>];
772     print_text ('Create a new group');
773     print q[</h1>
774 wakaba 1.1
775     <form action=new-group accept-charset=utf-8 method=post>
776    
777 wakaba 1.3 <p><strong>];
778     print_text ('Group id');
779     print q[</strong>: <input type=text name=group-id
780     maxlength=20 size=10 required pattern="[0-9a-z-]{4,20}"> (];
781     print_text ('Use [0-9a-z-]{4,20}.');
782     print q[) <p><input type=submit value="];
783     print_text ('Create');
784     print q["></form>];
785 wakaba 1.1 exit;
786     }
787     } elsif (@path == 1 and $path[0] eq '') {
788     my $user_id = $cgi->remote_user;
789     forbidden () if not defined $user_id or $user_id !~ /\A[0-9a-z-]+\z/;
790    
791 wakaba 1.2 redirect (303, 'See other', 'users/' . $user_id . '/');
792 wakaba 1.1 exit;
793     } elsif (@path == 0) {
794 wakaba 1.2 redirect (301, 'Moved', 'edit/');
795 wakaba 1.1 exit;
796     }
797    
798     print_error (404, 'Not found');
799     exit;
800    
801     sub print_list_section (%) {
802     my %opt = @_;
803     $opt{level} ||= 3;
804    
805     print q[<section id="] . htescape ($opt{id});
806 wakaba 1.3 print q["><h] . $opt{level} . q[>];
807     print_text ($opt{title});
808 wakaba 1.1 print q[</h] . $opt{level} . q[><ul>];
809     for my $item (sort {$a cmp $b} @{$opt{items}}) {
810     print q[<li>];
811     $opt{print_item}->($item);
812     }
813     print q[</ul></section>];
814     } # print_list_section
815    
816 wakaba 1.2 sub print_prop_list ($$@) {
817     my $ac = shift;
818     my $prop_hash = shift;
819    
820     for my $prop (@_) {
821     if ($prop->{public}) {
822 wakaba 1.3 print q[<p><strong>];
823     print_text ($prop->{label});
824     print q[</strong>: ];
825 wakaba 1.2 print $prop_hash->{$prop->{name}};
826     }
827    
828     if ($ac->{write}) {
829     print q[<form action="prop" accept-charset=utf-8 method=post>];
830     print q[<input type=hidden name=name value="], htescape ($prop->{name}), q[">];
831     if ($prop->{field_type} eq 'textarea') {
832 wakaba 1.3 print q[<p><label><strong>];
833     print_text ($prop->{label});
834 wakaba 1.2 print q[</strong>: <br><textarea name="value"];
835     print q[>], htescape ($prop_hash->{$prop->{name}} // '');
836     print q[</textarea></label>];
837 wakaba 1.3 print q[<p><input type=submit value="];
838     print_text ('Save');
839     print q[">];
840 wakaba 1.2 } else {
841 wakaba 1.3 print q[<p><label><strong>];
842     print_text ($prop->{label});
843 wakaba 1.2 print q[</strong>: <input type="] . $prop->{field_type};
844     print q[" name="value" ];
845     print q[value="], htescape ($prop_hash->{$prop->{name}} // '');
846     print q["></label> ];
847 wakaba 1.3 print q[<input type=submit value="];
848     print_text ('Save');
849     print q[">];
850 wakaba 1.2 }
851     print q[</form>];
852     }
853     }
854     } # print_prop_list
855    
856 wakaba 1.1 sub check_access_right (%) {
857     my %opt = @_;
858    
859     my $user_id = $cgi->remote_user;
860     forbidden () if not defined $user_id or $user_id !~ /\A[0-9a-z-]+\z/;
861    
862     my $user_prop = get_user_prop ($user_id);
863     forbidden () unless $user_prop;
864    
865 wakaba 1.2 my $ac = {};
866     my $return_ac;
867    
868 wakaba 1.1 if ($opt{allowed_users}->{$user_id}) {
869 wakaba 1.2 $ac->{write} = 1;
870     $return_ac = 1;
871 wakaba 1.1 }
872    
873     for my $group_id (keys %{$opt{allowed_groups} or {}}) {
874     my $group_prop = get_group_prop ($group_id);
875     next unless $group_prop;
876    
877     my $gs = $user_prop->{'group.' . $group_id};
878     if ($gs->{member}) {
879     return {write => 1, read_group_member_list => 1};
880     }
881     }
882    
883     if (defined $opt{group_context}) {
884     my $group_prop = get_group_prop ($opt{group_context});
885     if ($group_prop) {
886 wakaba 1.2 if (defined $group_prop->{admin_group}) {
887     my $ag_prop = get_group_prop ($group_prop->{admin_group});
888     if ($ag_prop and
889     $user_prop->{'group.' . $group_prop->{admin_group}}->{member}) {
890     return {write => 1, read_group_member_list => 1};
891     }
892     }
893    
894 wakaba 1.1 my $gs = $user_prop->{'group.' . $opt{group_context}};
895     if ($gs->{member}) {
896     $return_ac = 1;
897     } elsif ($gs->{invited}) {
898     $return_ac = 1;
899     } elsif ($group_prop->{join_condition}->{acception}) {
900     $return_ac = 1;
901     } elsif (not $group_prop->{join_condition}->{invitation}) {
902     $return_ac = 1;
903     }
904     }
905     }
906    
907     return $ac if $return_ac;
908    
909     forbidden ();
910     } # check_access_right
911    
912     sub forbidden () {
913     my $user = $cgi->remote_user;
914     if (defined $user) {
915 wakaba 1.3 print_error (403, q[Forbidden (you've logged in as %s)], $user);
916 wakaba 1.1 } else {
917     print_error (403, 'Forbidden');
918     }
919     exit;
920     } # forbidden
921 wakaba 1.2
922     sub redirect ($$$) {
923     my ($code, $status, $url) = @_;
924    
925     my $abs_url = get_absolute_url ($url);
926    
927     print qq[Status: $code $status
928     Location: $abs_url
929     Content-Type: text/html; charset=us-ascii
930    
931     See <a href="@{[htescape ($abs_url)]}">other page</a>.];
932     } # redirect
933 wakaba 1.1
934     sub percent_decode ($) {
935     return $dom->create_uri_reference ($_[0])
936     ->get_iri_reference
937     ->uri_reference;
938     } # percent_decode
939    
940     sub get_absolute_url ($) {
941     return $dom->create_uri_reference ($_[0])
942     ->get_absolute_reference ($cgi->request_uri)
943     ->get_iri_reference
944     ->uri_reference;
945     } # get_absolute_url

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24