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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.5 - (hide annotations) (download)
Thu Oct 30 12:11:51 2008 UTC (15 years, 6 months ago) by wakaba
Branch: MAIN
Changes since 1.4: +17 -3 lines
Favicon support

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.5 <link rel=stylesheet href="/www/style/html/xhtml">];
446     if (defined $group_prop->{favicon_url}) {
447     print q[<link rel=icon href="], htescape ($group_prop->{favicon_url});
448     print q[">];
449     }
450     print q[<h1>];
451     if (defined $group_prop->{favicon_url}) {
452     print q[<img src="], htescape ($group_prop->{favicon_url});
453     print q[" alt="">];
454     }
455 wakaba 1.3 print_text ('Group %s', sub { print $e_group_id });
456     print q[</h1>];
457    
458     print q[<section id=props><h2>];
459     print_text ('Properties');
460     print q[</h2>];
461 wakaba 1.2
462     print_prop_list ($ac, $group_prop,
463     {
464     name => 'desc',
465     label => 'Description',
466     field_type => 'textarea',
467     public => 1,
468     },
469     {
470     name => 'admin_group',
471     label => 'Administrative group',
472     field_type => 'text',
473     },
474 wakaba 1.5 {
475     name => 'favicon_url',
476     label => 'Group icon URL',
477     field_type => 'url',
478     },
479 wakaba 1.2 );
480    
481 wakaba 1.3 print q[</section><section id=members><h2>];
482     print_text ('Members');
483     print q[</h2>];
484 wakaba 1.1
485     if ($ac->{read_group_member_list}) {
486     my @members;
487     my @apps;
488     my @invited;
489     for my $user_id (get_all_users ()) {
490     my $user_prop = get_user_prop ($user_id);
491     my $gs = $user_prop->{'group.' . $group_id};
492     if ($gs->{member}) {
493     push @members, $user_id;
494     } elsif ($gs->{no_approval}) {
495     push @apps, $user_id;
496     } elsif ($gs->{invited}) {
497     push @invited, $user_id;
498     }
499     }
500    
501     if (@members) {
502     print_list_section
503     (id => 'formal-members',
504     title => 'Formal members',
505     items => \@members,
506     print_item => sub {
507     my $user_id = shift;
508     print q[<form action="user.] . htescape ($user_id);
509 wakaba 1.3 print q[" accept-charset=utf-8 method=post>];
510 wakaba 1.1 print qq[<a href="../../users/@{[htescape ($user_id)]}/">];
511     print '' . htescape ($user_id) . q[</a> ];
512     print q[<input type=hidden name=action value=unapprove>];
513 wakaba 1.3 print q[<input type=submit value="];
514     print_text ('Kick');
515     print q["></form>];
516 wakaba 1.1 });
517     }
518    
519     if (@apps) {
520     print_list_section
521     (id => 'non-approved-users',
522     title => 'Users who are waiting for the approval to join',
523     items => \@apps,
524     print_item => sub {
525     my $user_id = shift;
526     print q[<form action="user.] . htescape ($user_id);
527     print q[" accept-charset=utf-8 method=post>];
528     print qq[<a href="../../users/@{[htescape ($user_id)]}/">];
529     print '' . htescape ($user_id) . q[</a> ];
530     print q[<input type=hidden name=action value=approve>];
531 wakaba 1.3 print q[<input type=submit value="];
532     print_text ('Approve');
533     print q["></form>];
534 wakaba 1.1 });
535     }
536    
537     if (@invited) {
538     print_list_section
539     (id => 'invited-users',
540     title => 'Users who are invited but not joined or are leaved',
541     items => \@invited,
542     print_item => sub {
543     my $user_id = shift;
544     print q[<form action="user.] . htescape ($user_id);
545     print q[" accept-charset=utf-8 method=post>];
546     print qq[<a href="../../users/@{[htescape ($user_id)]}/">];
547     print '' . htescape ($user_id), q[</a> ];
548     print q[<input type=hidden name=action value=unapprove>];
549 wakaba 1.3 print q[<input type=submit value="];
550     print_text ('Cancel invitation');
551     print q["></form>];
552 wakaba 1.1 });
553     }
554     }
555    
556     my $join_condition = $group_prop->{join_condition};
557     my $disabled = $ac->{write} ? '' : 'disabled';
558 wakaba 1.3 print qq[<section id=member-approval><h3>];
559     print_text ('Member approval policy');
560     print qq[</h3>
561 wakaba 1.1
562     <form action=join-condition method=post accept-charset=utf-8>
563    
564     <p><label><input type=radio name=condition value=invitation $disabled
565 wakaba 1.3 @{[$join_condition->{invitation} ? 'checked' : '']}> ];
566     print_text ('A user who is invited by an administrator of the group can join the group.');
567     print qq[</label>
568 wakaba 1.1
569     <p><label><input type=radio name=condition value=approval $disabled
570     @{[(not $join_condition->{invitation} and $join_condition->{approval})
571 wakaba 1.3 ? 'checked' : '']}> ];
572     print_text ('A user who is invited or approved by an administrator of the group can join the group.');
573     print qq[</label>
574 wakaba 1.1
575     <p><label><input type=radio name=condition value=anyone $disabled
576     @{[(not $join_condition->{invitation} and not
577 wakaba 1.3 $join_condition->{approval}) ? 'checked' : '']}> ];
578     print_text ('Any user can join the group.');
579     print q[</label>];
580     unless ($disabled) {
581     print q[<p><input type=submit value="];
582     print_text ('Change');
583     print q[">];
584     }
585     print q[</form></section>];
586 wakaba 1.1
587     if ($ac->{write}) {
588 wakaba 1.3 print q[<section id=member-invitation><h3>];
589     print_text ('Invite a user');
590     print q[</h3>
591 wakaba 1.1
592     <form action=invite-user accept-charset=utf-8 method=post>
593    
594 wakaba 1.3 <p><strong>];
595     print_text ('User id');
596     print q[</strong>: <input type=text name=user-id
597 wakaba 1.1 maxlength=20 size=10 required pattern="[0-9a-z-]{4,20}">
598    
599 wakaba 1.3 <p><input type=submit value="];
600     print_text ('Invite');
601     print q["></form></section>];
602 wakaba 1.1 }
603    
604     print q[</section>];
605    
606     exit;
607     }
608     } elsif ($path[2] eq 'join-condition') {
609     forbidden () unless $ac->{write};
610    
611     if ($cgi->request_method eq 'POST') {
612     lock_start ();
613     my $group_prop = get_group_prop ($group_id);
614     if ($group_prop) {
615     binmode STDOUT, ':encoding(utf-8)';
616    
617     my $new_condition = $cgi->get_parameter ('condition');
618     if ($new_condition eq 'invitation') {
619     $group_prop->{join_condition}->{invitation} = 1;
620     $group_prop->{join_condition}->{approval} = 1;
621     } elsif ($new_condition eq 'approval') {
622     $group_prop->{join_condition}->{approval} = 1;
623     delete $group_prop->{join_condition}->{invitation};
624     } else {
625     delete $group_prop->{join_condition}->{invitation};
626     delete $group_prop->{join_condition}->{approval};
627     }
628    
629     set_group_prop ($group_id, $group_prop);
630     commit ();
631    
632     print "Status: 204 join-condition property updated\n\n";
633     exit;
634     }
635     }
636 wakaba 1.2 } elsif ($path[2] eq 'prop') {
637     forbidden () unless $ac->{write};
638    
639     if ($cgi->request_method eq 'POST') {
640     lock_start ();
641     my $group_prop = get_group_prop ($group_id);
642     if ($group_prop) {
643     binmode STDOUT, ':encoding(utf-8)';
644    
645     my $prop_name = $cgi->get_parameter ('name');
646     if (defined $prop_name and
647 wakaba 1.5 {desc => 1, admin_group => 1,
648     favicon_url => 1}->{$prop_name}) {
649 wakaba 1.2 $group_prop->{$prop_name} = $cgi->get_parameter ('value');
650    
651     set_group_prop ($group_id, $group_prop);
652     commit ();
653    
654     print "Status: 204 Property updated\n\n";
655     exit;
656     } else {
657     print_error (400, 'Bad property');
658     exit;
659     }
660     }
661     }
662 wakaba 1.1 } elsif ($path[2] =~ /\Auser\.([0-9a-z-]+)\z/ or
663     $path[2] eq 'invite-user') {
664     my $user_id = $1 // $cgi->get_parameter ('user-id') // '';
665     if ($user_id =~ /\A[0-9a-z-]+\z/ and
666     $cgi->request_method eq 'POST') {
667     forbidden () unless $ac->{write};
668    
669     lock_start ();
670     my $group_prop = get_group_prop ($group_id);
671     my $user_prop = get_user_prop ($user_id);
672     if ($group_prop and $user_prop) {
673     binmode STDOUT, ':encoding(utf-8)';
674    
675     my $gs = ($user_prop->{'group.' . $group_id} ||= {});
676    
677     my $action = $cgi->get_parameter ('action');
678     $action = 'approve' if $path[2] eq 'invite-user';
679     my $status;
680     if ($action eq 'approve') {
681     if ($gs->{member}) {
682     $status = 'He is a member';
683     #
684     } elsif ($gs->{no_approval}) {
685     $gs->{member} = 1;
686     delete $gs->{no_approval};
687     $status = 'Registered';
688     #
689     } elsif ($gs->{invited}) {
690     $status = 'He has been invited';
691     #
692     } else {
693     $gs->{invited} = 1;
694     $status = 'Invited';
695     #
696     }
697     } elsif ($action eq 'unapprove') {
698     if ($gs->{member}) {
699     delete $gs->{member};
700     delete $gs->{invited};
701     $status = 'Unregistered';
702     #
703     } elsif ($gs->{invited}) {
704     delete $gs->{invited};
705     $status = 'Invitation canceled';
706     #
707     } else {
708     $status = 'Not a member';
709     #
710     }
711     } else {
712     print_error (400, 'Bad action parameter');
713     exit;
714     }
715    
716     set_user_prop ($user_id, $user_prop);
717     regenerate_htpasswd_and_htgroup ();
718     commit ();
719    
720 wakaba 1.4 #print "Status: 204 $status\n\n";
721     redirect (303, $status, './#members');
722 wakaba 1.1 exit;
723     }
724     }
725     }
726     } elsif (@path == 1 and $path[0] eq 'new-group') {
727     check_access_right (allowed_groups => {'admin-groups' => 1});
728    
729     if ($cgi->request_method eq 'POST') {
730     lock_start ();
731     binmode STDOUT, ':encoding(utf-8)';
732    
733     my $group_id = $cgi->get_parameter ('group-id');
734    
735     if ($group_id !~ /\A[0-9a-z-]{4,20}\z/) {
736 wakaba 1.3 print_error (400,
737     q[Group id %s is invalid; use characters [0-9a-z-]{4,20}],
738     $group_id);
739 wakaba 1.1 exit;
740     }
741    
742     if (get_group_prop ($group_id)) {
743 wakaba 1.3 print_error (400, q[Group id %s is already used], $group_id);
744 wakaba 1.1 exit;
745     }
746    
747     my $group_prop = {id => $group_id};
748     set_group_prop ($group_id, $group_prop);
749    
750     commit ();
751    
752     my $group_url = get_absolute_url ('groups/' . $group_id . '/');
753    
754     print qq[Status: 201 Group registered
755     Location: $group_url
756     Content-Type: text/html; charset=utf-8
757    
758     <!DOCTYPE HTML>
759     <html lang=en>
760 wakaba 1.3 <title>];
761     print_text ('Group %s registered', sub { print '', htescape ($group_id) });
762     print q[</title>
763 wakaba 1.1 <link rel=stylesheet href="/www/style/html/xhtml">
764 wakaba 1.3 <h1>];
765     print_text ('Group %s registered', sub { print '', htescape ($group_id) });
766     print q[</h1><p>];
767     print_text ('The new group is created successfully.');
768     print q[<p>];
769     print_text ('See %s.', sub {
770     print qq[<a href="@{[htescape ($group_url)]}">];
771     print_text ('the group information page');
772     print qq[</a>];
773     });
774 wakaba 1.1 exit;
775     } else {
776     binmode STDOUT, ":encoding(utf-8)";
777 wakaba 1.3 print q[Content-Type: text/html; charset=utf-8
778 wakaba 1.1
779     <!DOCTYPE HTML>
780     <html lang=en>
781 wakaba 1.3 <title>];
782     print_text ('Create a new group');
783     print q[</title>
784 wakaba 1.1 <link rel=stylesheet href="/www/style/html/xhtml">
785 wakaba 1.3 <h1>];
786     print_text ('Create a new group');
787     print q[</h1>
788 wakaba 1.1
789     <form action=new-group accept-charset=utf-8 method=post>
790    
791 wakaba 1.3 <p><strong>];
792     print_text ('Group id');
793     print q[</strong>: <input type=text name=group-id
794     maxlength=20 size=10 required pattern="[0-9a-z-]{4,20}"> (];
795     print_text ('Use [0-9a-z-]{4,20}.');
796     print q[) <p><input type=submit value="];
797     print_text ('Create');
798     print q["></form>];
799 wakaba 1.1 exit;
800     }
801     } elsif (@path == 1 and $path[0] eq '') {
802     my $user_id = $cgi->remote_user;
803     forbidden () if not defined $user_id or $user_id !~ /\A[0-9a-z-]+\z/;
804    
805 wakaba 1.2 redirect (303, 'See other', 'users/' . $user_id . '/');
806 wakaba 1.1 exit;
807     } elsif (@path == 0) {
808 wakaba 1.2 redirect (301, 'Moved', 'edit/');
809 wakaba 1.1 exit;
810     }
811    
812     print_error (404, 'Not found');
813     exit;
814    
815     sub print_list_section (%) {
816     my %opt = @_;
817     $opt{level} ||= 3;
818    
819     print q[<section id="] . htescape ($opt{id});
820 wakaba 1.3 print q["><h] . $opt{level} . q[>];
821     print_text ($opt{title});
822 wakaba 1.1 print q[</h] . $opt{level} . q[><ul>];
823     for my $item (sort {$a cmp $b} @{$opt{items}}) {
824     print q[<li>];
825     $opt{print_item}->($item);
826     }
827     print q[</ul></section>];
828     } # print_list_section
829    
830 wakaba 1.2 sub print_prop_list ($$@) {
831     my $ac = shift;
832     my $prop_hash = shift;
833    
834     for my $prop (@_) {
835     if ($prop->{public}) {
836 wakaba 1.3 print q[<p><strong>];
837     print_text ($prop->{label});
838     print q[</strong>: ];
839 wakaba 1.2 print $prop_hash->{$prop->{name}};
840     }
841    
842     if ($ac->{write}) {
843     print q[<form action="prop" accept-charset=utf-8 method=post>];
844     print q[<input type=hidden name=name value="], htescape ($prop->{name}), q[">];
845     if ($prop->{field_type} eq 'textarea') {
846 wakaba 1.3 print q[<p><label><strong>];
847     print_text ($prop->{label});
848 wakaba 1.2 print q[</strong>: <br><textarea name="value"];
849     print q[>], htescape ($prop_hash->{$prop->{name}} // '');
850     print q[</textarea></label>];
851 wakaba 1.3 print q[<p><input type=submit value="];
852     print_text ('Save');
853     print q[">];
854 wakaba 1.2 } else {
855 wakaba 1.3 print q[<p><label><strong>];
856     print_text ($prop->{label});
857 wakaba 1.2 print q[</strong>: <input type="] . $prop->{field_type};
858     print q[" name="value" ];
859     print q[value="], htescape ($prop_hash->{$prop->{name}} // '');
860     print q["></label> ];
861 wakaba 1.3 print q[<input type=submit value="];
862     print_text ('Save');
863     print q[">];
864 wakaba 1.2 }
865     print q[</form>];
866     }
867     }
868     } # print_prop_list
869    
870 wakaba 1.1 sub check_access_right (%) {
871     my %opt = @_;
872    
873     my $user_id = $cgi->remote_user;
874     forbidden () if not defined $user_id or $user_id !~ /\A[0-9a-z-]+\z/;
875    
876     my $user_prop = get_user_prop ($user_id);
877     forbidden () unless $user_prop;
878    
879 wakaba 1.2 my $ac = {};
880     my $return_ac;
881    
882 wakaba 1.1 if ($opt{allowed_users}->{$user_id}) {
883 wakaba 1.2 $ac->{write} = 1;
884     $return_ac = 1;
885 wakaba 1.1 }
886    
887     for my $group_id (keys %{$opt{allowed_groups} or {}}) {
888     my $group_prop = get_group_prop ($group_id);
889     next unless $group_prop;
890    
891     my $gs = $user_prop->{'group.' . $group_id};
892     if ($gs->{member}) {
893     return {write => 1, read_group_member_list => 1};
894     }
895     }
896    
897     if (defined $opt{group_context}) {
898     my $group_prop = get_group_prop ($opt{group_context});
899     if ($group_prop) {
900 wakaba 1.2 if (defined $group_prop->{admin_group}) {
901     my $ag_prop = get_group_prop ($group_prop->{admin_group});
902     if ($ag_prop and
903     $user_prop->{'group.' . $group_prop->{admin_group}}->{member}) {
904     return {write => 1, read_group_member_list => 1};
905     }
906     }
907    
908 wakaba 1.1 my $gs = $user_prop->{'group.' . $opt{group_context}};
909     if ($gs->{member}) {
910     $return_ac = 1;
911     } elsif ($gs->{invited}) {
912     $return_ac = 1;
913     } elsif ($group_prop->{join_condition}->{acception}) {
914     $return_ac = 1;
915     } elsif (not $group_prop->{join_condition}->{invitation}) {
916     $return_ac = 1;
917     }
918     }
919     }
920    
921     return $ac if $return_ac;
922    
923     forbidden ();
924     } # check_access_right
925    
926     sub forbidden () {
927     my $user = $cgi->remote_user;
928     if (defined $user) {
929 wakaba 1.3 print_error (403, q[Forbidden (you've logged in as %s)], $user);
930 wakaba 1.1 } else {
931     print_error (403, 'Forbidden');
932     }
933     exit;
934     } # forbidden
935 wakaba 1.2
936     sub redirect ($$$) {
937     my ($code, $status, $url) = @_;
938    
939     my $abs_url = get_absolute_url ($url);
940    
941     print qq[Status: $code $status
942     Location: $abs_url
943     Content-Type: text/html; charset=us-ascii
944    
945     See <a href="@{[htescape ($abs_url)]}">other page</a>.];
946     } # redirect
947 wakaba 1.1
948     sub percent_decode ($) {
949     return $dom->create_uri_reference ($_[0])
950     ->get_iri_reference
951     ->uri_reference;
952     } # percent_decode
953    
954     sub get_absolute_url ($) {
955     return $dom->create_uri_reference ($_[0])
956     ->get_absolute_reference ($cgi->request_uri)
957     ->get_iri_reference
958     ->uri_reference;
959     } # get_absolute_url

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24