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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.6 - (hide annotations) (download)
Sat Nov 1 10:13:14 2008 UTC (15 years, 6 months ago) by wakaba
Branch: MAIN
Changes since 1.5: +10 -0 lines
Send a mail message when a significant change occurs

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

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24