]>
Commit | Line | Data |
---|---|---|
0eb78304 TC |
1 | package BSE::UI::User; |
2 | use strict; | |
3 | use base 'BSE::UI::Dispatch'; | |
4 | use BSE::Util::Tags qw(tag_hash tag_error_img tag_hash_plain); | |
5 | use DevHelp::HTML qw(:default popup_menu); | |
6 | use BSE::Util::Iterate; | |
3fb296b8 TC |
7 | use BSE::Util::SQL qw/now_datetime/; |
8 | use DevHelp::Date qw(dh_strftime_sql_datetime); | |
32696f84 | 9 | use base 'BSE::UI::UserCommon'; |
0eb78304 TC |
10 | |
11 | my %actions = | |
12 | ( | |
f5505b76 | 13 | info => 1, |
0eb78304 TC |
14 | bookseminar => 1, |
15 | bookconfirm => 1, | |
16 | book => 1, | |
17 | bookcomplete => 1, | |
3fb296b8 TC |
18 | bookinglist => 1, |
19 | bookingdetail => 1, | |
20 | cancelbookingconfirm => 1, | |
21 | cancelbooking => 1, | |
22 | editbooking => 1, | |
23 | savebooking => 1, | |
f5505b76 TC |
24 | wishlistadd => 1, |
25 | wishlistdel => 1, | |
26 | wishlistup => 1, | |
27 | wishlistdown => 1, | |
28 | wishlisttop => 1, | |
29 | wishlistbottom => 1, | |
30 | wishlist => 1, | |
0eb78304 TC |
31 | ); |
32 | ||
33 | sub default_action { | |
f5505b76 | 34 | 'info'; |
0eb78304 TC |
35 | } |
36 | ||
37 | sub actions { | |
38 | \%actions; | |
39 | } | |
40 | ||
f5505b76 TC |
41 | sub req_info { |
42 | my ($self, $req) = @_; | |
43 | ||
44 | my $user = $req->siteuser; | |
45 | ||
46 | my $cfg = $req->cfg; | |
47 | my $cgi = $req->cgi; | |
48 | ||
49 | require BSE::TB::Orders; | |
50 | my @orders = sort { $b->{orderDate} cmp $a->{orderDate} | |
51 | || $b->{id} <=> $a->{id} } | |
52 | BSE::TB::Orders->getBy(userId=>$user->{userId}); | |
53 | ||
54 | my $must_be_paid = $cfg->entryBool('downloads', 'must_be_paid', 0); | |
55 | my $must_be_filled = $cfg->entryBool('downloads', 'must_be_filled', 0); | |
56 | ||
57 | my $it = BSE::Util::Iterate->new; | |
58 | my $order_index; | |
59 | my $item_index; | |
60 | my @items; | |
61 | my %acts; | |
62 | my $product; | |
63 | my @files; | |
64 | my $file_index; | |
65 | my $message = $req->message(); | |
66 | %acts = | |
67 | ( | |
68 | $req->dyn_user_tags, | |
69 | message => $message, | |
70 | BSE::Util::Tags->make_iterator(\@orders, 'order', 'orders', | |
71 | \$order_index), | |
72 | BSE::Util::Tags-> | |
73 | make_dependent_iterator(\$order_index, | |
74 | sub { | |
75 | require BSE::TB::OrderItems; | |
76 | @items = BSE::TB::OrderItems-> | |
77 | getBy(orderId=>$orders[$_[0]]{id}); | |
78 | }, | |
79 | 'item', 'items', \$item_index), | |
80 | BSE::Util::Tags-> | |
81 | make_dependent_iterator(\$order_index, | |
82 | sub { | |
83 | @files = BSE::DB->query | |
84 | (orderFiles=>$orders[$_[0]]{id}); | |
85 | }, | |
86 | 'orderfile', 'orderfiles', \$file_index), | |
87 | product => | |
88 | sub { | |
89 | require Products; | |
90 | $product = Products->getByPkey($items[$item_index]{productId}) | |
91 | unless $product && $product->{id} == $items[$item_index]{productId}; | |
92 | CGI::escapeHTML($product->{$_[0]}); | |
93 | }, | |
94 | BSE::Util::Tags-> | |
95 | make_multidependent_iterator | |
96 | ([ \$item_index, \$order_index], | |
97 | sub { | |
98 | require 'ArticleFiles.pm'; | |
99 | @files = sort { $b->{displayOrder} <=> $a->{displayOrder} } | |
6430ee52 | 100 | BSE::TB::ArticleFiles->getBy(articleId=>$items[$item_index]{productId}); |
f5505b76 TC |
101 | }, |
102 | 'prodfile', 'prodfiles', \$file_index), | |
103 | ifFileAvail => | |
104 | sub { | |
105 | if ($file_index >= 0 && $file_index < @files) { | |
106 | return 1 if !$files[$file_index]{forSale}; | |
107 | } | |
108 | return 0 if $must_be_paid && !$orders[$order_index]{paidFor}; | |
109 | return 0 if $must_be_filled && !$orders[$order_index]{filled}; | |
110 | return 1; | |
111 | }, | |
112 | $it->make_iterator([ \&iter_usersubs, $user ], | |
113 | 'subscription', 'subscriptions'), | |
114 | $it->make_iterator([ \&iter_sembookings, $user ], | |
115 | 'booking', 'bookings'), | |
116 | ); | |
117 | ||
118 | return $req->dyn_response('user/userpage', \%acts); | |
119 | } | |
120 | ||
121 | sub iter_usersubs { | |
122 | my ($user) = @_; | |
123 | ||
124 | $user->subscribed_services; | |
125 | } | |
126 | ||
127 | sub iter_sembookings { | |
128 | my ($user) = @_; | |
129 | ||
130 | $user->seminar_bookings_detail; | |
131 | } | |
132 | ||
0eb78304 TC |
133 | sub req_bookseminar { |
134 | my ($self, $req, $errors) = @_; | |
135 | ||
136 | my $cgi = $req->cgi; | |
137 | my $seminar_id = $cgi->param('id'); | |
138 | defined $seminar_id && $seminar_id =~ /^\d+$/ | |
139 | or return $self->error($req, "Seminar id parameter missing"); | |
140 | ||
141 | require BSE::TB::Seminars; | |
142 | my $seminar = BSE::TB::Seminars->getByPkey($seminar_id) | |
143 | or return $self->error($req, "Unknown seminar"); | |
144 | ||
145 | $seminar->{retailPrice} == 0 | |
146 | or return $self->error($req, "This is only available for free seminars"); | |
147 | ||
148 | my @sessions = $seminar->session_info_unbooked($req->siteuser); | |
149 | my $message = $req->message($errors); | |
150 | @sessions | |
151 | or $message = "You are already booked for every session of this seminar"; | |
152 | my @opt_names = split /,/, $seminar->{options}; | |
153 | my @opt_values = map { ($cgi->param($_))[0] } @opt_names; | |
154 | my @options = $seminar->option_descs($req->cfg, \@opt_values); | |
155 | ||
156 | my $it = BSE::Util::Iterate->new; | |
157 | my $current_option; | |
158 | my %acts; | |
159 | %acts = | |
160 | ( | |
161 | $req->dyn_user_tags(), | |
162 | seminar => [ \&tag_hash, $seminar ], | |
163 | message => escape_html($message), | |
164 | error_img => [ \&tag_error_img, $req->cfg, $errors ], | |
165 | $it->make_iterator(undef, 'session', 'sessions', \@sessions), | |
166 | $it->make_iterator(undef, 'option', 'options', \@options, | |
167 | undef, undef, \$current_option), | |
3fb296b8 | 168 | option_popup => [ \&tag_option_popup, $cgi, \$current_option ], |
0eb78304 TC |
169 | ); |
170 | ||
171 | return $req->dyn_response('user/bookseminar', \%acts); | |
172 | } | |
173 | ||
0eb78304 TC |
174 | sub req_bookconfirm { |
175 | my ($self, $req) = @_; | |
176 | ||
177 | my $cgi = $req->cgi; | |
178 | my $seminar_id = $cgi->param('id'); | |
179 | defined $seminar_id && $seminar_id =~ /^\d+$/ | |
180 | or return $self->error($req, "Seminar id parameter missing"); | |
181 | ||
182 | require BSE::TB::Seminars; | |
183 | my $seminar = BSE::TB::Seminars->getByPkey($seminar_id) | |
184 | or return $self->error($req, "Unknown seminar"); | |
185 | ||
186 | $seminar->{retailPrice} == 0 | |
187 | or return $self->error($req, "This is only available for free seminars"); | |
188 | ||
189 | my $session_id = $cgi->param('session_id'); | |
190 | defined $session_id && $session_id =~ /^\d+$/ | |
191 | or return $self->req_bookseminar($req, { session_id => "Please select a session" }); | |
192 | ||
193 | require BSE::TB::SeminarSessions; | |
194 | my $session = BSE::TB::SeminarSessions->getByPkey($session_id) | |
195 | or return $self->req_bookseminar($req, { session_id => "Unknown session id" }); | |
196 | ||
197 | # make sure the user isn't already booked for this | |
198 | $session->get_booking($req->siteuser) | |
199 | and return $self->req_bookseminar($req, { session_id => "You are already booked for this session"} ); | |
200 | ||
201 | my @opt_names = split /,/, $seminar->{options}; | |
202 | my @opt_values = map { ($cgi->param($_))[0] } @opt_names; | |
203 | my @options = $seminar->option_descs($req->cfg, \@opt_values); | |
204 | ||
205 | my $it = BSE::Util::Iterate->new; | |
206 | my $current_option; | |
207 | my %acts; | |
208 | %acts = | |
209 | ( | |
210 | $req->dyn_user_tags(), | |
211 | seminar => [ \&tag_hash, $seminar ], | |
212 | session => [ \&tag_hash, $session ], | |
213 | location => [ \&tag_hash, $session->location ], | |
214 | $it->make_iterator(undef, 'option', 'options', \@options, | |
215 | undef, undef, \$current_option), | |
216 | ); | |
217 | ||
218 | return $req->dyn_response('user/bookconfirm', \%acts); | |
219 | } | |
220 | ||
221 | sub req_book { | |
222 | my ($self, $req) = @_; | |
223 | ||
224 | my $cgi = $req->cgi; | |
225 | my $cfg = $req->cfg; | |
226 | my $seminar_id = $cgi->param('id'); | |
227 | defined $seminar_id && $seminar_id =~ /^\d+$/ | |
228 | or return $self->error($req, "Seminar id parameter missing"); | |
229 | ||
230 | require BSE::TB::Seminars; | |
231 | my $seminar = BSE::TB::Seminars->getByPkey($seminar_id) | |
232 | or return $self->error($req, "Unknown seminar"); | |
233 | ||
234 | $seminar->{retailPrice} == 0 | |
235 | or return $self->error($req, "This is only available for free seminars"); | |
236 | ||
237 | my $session_id = $cgi->param('session_id'); | |
238 | defined $session_id && $session_id =~ /^\d+$/ | |
239 | or return $self->req_bookseminar($req, { session_id => "Please select a session" }); | |
240 | ||
241 | require BSE::TB::SeminarSessions; | |
242 | my $session = BSE::TB::SeminarSessions->getByPkey($session_id) | |
243 | or return $self->req_bookseminar($req, { session_id => "Unknown session id" }); | |
244 | ||
245 | # make sure the user isn't already booked for this | |
246 | require BSE::TB::SeminarBookings; | |
247 | $session->get_booking($req->siteuser) | |
248 | and return $self->req_bookseminar($req, { session_id => "You are already booked for this session"} ); | |
249 | ||
250 | my @opt_names = split /,/, $seminar->{options}; | |
251 | my @opt_values = map { ($cgi->param($_))[0] } @opt_names; | |
252 | ||
253 | my %more; | |
254 | for my $name (qw/customer_instructions support_notes roll_present/) { | |
255 | my $value = $cgi->param($name); | |
256 | $value and $more{$name} = $value; | |
257 | } | |
258 | $more{roll_present} = 0; | |
259 | $more{options} = join(',', @opt_values); | |
260 | ||
261 | my $booking; | |
262 | eval { | |
263 | $booking = $session->add_attendee($req->siteuser, %more); | |
264 | }; | |
265 | if ($@) { | |
266 | if ($@ =~ /duplicate/) { | |
267 | return $self->req_bookseminar($req, { session_id => "You appear to be already booked for this seminar" }); | |
268 | } | |
269 | else { | |
270 | return $self->req_bookseminar($req, { _error => $@ }); | |
271 | } | |
272 | } | |
273 | ||
274 | my $message; | |
275 | if ($cfg->entry('seminars', 'notify_user_booking', 1)) { | |
276 | my $email = $cfg->entry('seminar', 'notify_user_booking_email') | |
277 | || $cfg->entry('shop', 'from', $Constants::SHOP_FROM); | |
0eb78304 TC |
278 | my $subject = $cfg->entry('seminar', 'notify_user_booking_subject', |
279 | 'A user has booked a seminar session'); | |
280 | my @sem_options = $seminar->option_descs($cfg, \@opt_values); | |
281 | my $it = DevHelp::Tags::Iterate->new; | |
282 | my %acts = | |
283 | ( | |
284 | BSE::Util::Tags->static(undef, $cfg), | |
285 | user => [ \&tag_hash_plain, $req->siteuser ], | |
286 | seminar => [ \&tag_hash_plain, $seminar ], | |
287 | session => [ \&tag_hash_plain, $session ], | |
288 | location => [ \&tag_hash_plain, $session->location ], | |
289 | booking => [ \&tag_hash_plain, $booking ], | |
290 | $it->make_iterator(undef, 'option', 'options', \@sem_options), | |
291 | ); | |
292 | require BSE::ComposeMail; | |
293 | my $mailer = BSE::ComposeMail->new(cfg => $cfg); | |
294 | unless ($mailer->send(to => $email, | |
0eb78304 TC |
295 | subject => $subject, |
296 | template => 'admin/user_book_seminar', | |
297 | acts => \%acts)) { | |
298 | $message = "Your seminar has been booked but there was an error sending an email notification to the system administrator:".$mailer->errstr; | |
299 | } | |
300 | } | |
301 | ||
302 | # refresh to the completion page | |
303 | my %params = | |
304 | ( | |
305 | a_bookcomplete => 1, | |
306 | _p => $self->controller_id, | |
307 | id => $booking->{id}, | |
308 | ); | |
309 | $message and $params{m} = $message; | |
310 | my $url = $ENV{SCRIPT_NAME} . '?' . | |
311 | join '&', map { "$_=". escape_uri($params{$_}) } keys %params; | |
312 | ||
313 | return BSE::Template->get_refresh($url, $req->cfg); | |
314 | } | |
315 | ||
316 | sub req_bookcomplete { | |
317 | my ($self, $req) = @_; | |
318 | ||
319 | my $id = $req->cgi->param('id'); | |
320 | defined $id || $id =~ /^\d+$/ | |
321 | or return $self->error($req, "No booking id supplied"); | |
322 | ||
323 | require BSE::TB::SeminarBookings; | |
324 | my $booking = BSE::TB::SeminarBookings->getByPkey($id); | |
325 | my $user = $req->siteuser; | |
326 | $booking && $booking->{siteuser_id} == $user->{id} | |
327 | or return $self->error($req, "No such booking found"); | |
328 | ||
329 | my $session = $booking->session; | |
330 | my $seminar = $session->seminar; | |
331 | my @opt_values = split /,/, $booking->{options}; | |
332 | my @options = $seminar->option_descs($req->cfg, \@opt_values); | |
333 | my %acts; | |
3fb296b8 | 334 | my $message ||= $req->message(); |
0eb78304 TC |
335 | my $it = BSE::Util::Iterate->new; |
336 | %acts = | |
337 | ( | |
338 | $req->dyn_user_tags(), | |
339 | seminar => [ \&tag_hash, $seminar ], | |
340 | session => [ \&tag_hash, $session ], | |
341 | location => [ \&tag_hash, $session->location ], | |
342 | booking => [ \&tag_hash, $booking ], | |
343 | message => escape_html($message), | |
344 | $it->make_iterator(undef, 'option', 'options', \@options), | |
345 | ); | |
346 | ||
347 | return $req->dyn_response('user/bookcomplete', \%acts); | |
348 | } | |
349 | ||
3fb296b8 TC |
350 | sub req_bookinglist { |
351 | my ($class, $req, $message) = @_; | |
352 | ||
353 | my @bookings = $req->siteuser->seminar_bookings_detail; | |
354 | my $now = now_datetime; | |
355 | for my $booking (@bookings) { | |
356 | $booking->{past} = $booking->{when_at} lt $now ? 1 : 0; | |
357 | } | |
358 | my $show_past = $req->cgi->param('show_past'); | |
359 | unless ($show_past) { | |
360 | @bookings = grep !$_->{past}, @bookings; | |
361 | } | |
362 | ||
363 | $message ||= $req->message; | |
364 | ||
365 | my $it = BSE::Util::Iterate->new; | |
366 | my %acts; | |
367 | %acts = | |
368 | ( | |
369 | $req->dyn_user_tags(), | |
370 | $it->make_iterator(undef, 'booking', 'bookings', \@bookings), | |
371 | message => escape_html($message), | |
372 | ); | |
373 | ||
374 | return $req->dyn_response('user/bookinglist', \%acts); | |
375 | } | |
376 | ||
377 | sub _show_booking { | |
378 | my ($class, $req, $template, $errors) = @_; | |
379 | ||
380 | my $cgi = $req->cgi; | |
381 | ||
382 | my $id = $cgi->param('id'); | |
383 | defined $id && $id =~ /^\d+$/ | |
384 | or return $class->req_bookinglist($req, "id parameter invalid"); | |
385 | ||
386 | require BSE::TB::SeminarBookings; | |
387 | my $booking = BSE::TB::SeminarBookings->getByPkey($id); | |
388 | $booking && $booking->{siteuser_id} == $req->siteuser->{id} | |
389 | or return $class->req_bookinglist($req, "booking $id not found"); | |
390 | ||
391 | my $session = $booking->session; | |
392 | ||
393 | my $seminar = $session->seminar; | |
394 | my @sem_options = | |
395 | $seminar->option_descs($req->cfg, [ split /,/, $booking->{options} ]); | |
396 | ||
397 | my $message = $req->message($errors); | |
398 | $message = escape_html($message); | |
399 | ||
400 | my $it = BSE::Util::Iterate->new; | |
401 | my %acts; | |
402 | %acts = | |
403 | ( | |
404 | $req->dyn_user_tags(), | |
405 | session => [ \&tag_hash, $session ], | |
406 | seminar => [ \&tag_hash, $seminar ], | |
407 | location => [ \&tag_hash, $session->location ], | |
408 | booking => [ \&tag_hash, $booking ], | |
409 | message => $message, | |
410 | $it->make_iterator(undef, 'option', 'options', \@sem_options), | |
411 | ); | |
412 | ||
413 | return $req->dyn_response($template, \%acts); | |
414 | } | |
415 | ||
416 | sub req_bookingdetail { | |
417 | my ($class, $req) = @_; | |
418 | ||
419 | return $class->_show_booking($req, 'user/bookingdetail'); | |
420 | } | |
421 | ||
422 | sub req_cancelbookingconfirm { | |
423 | my ($class, $req, $message) = @_; | |
424 | ||
425 | return $class->_show_booking($req, 'user/cancelbooking', $message); | |
426 | } | |
427 | ||
428 | sub req_cancelbooking { | |
429 | my ($class, $req) = @_; | |
430 | ||
431 | my $cgi = $req->cgi; | |
432 | ||
433 | my $id = $cgi->param('id'); | |
434 | defined $id && $id =~ /^\d+$/ | |
435 | or return $class->req_bookinglist($req, "id parameter invalid"); | |
436 | ||
437 | my $siteuser = $req->siteuser; | |
438 | ||
439 | require BSE::TB::SeminarBookings; | |
440 | my $booking = BSE::TB::SeminarBookings->getByPkey($id); | |
441 | $booking && $booking->{siteuser_id} == $siteuser->{id} | |
442 | or return $class->req_bookinglist($req, "booking $id not found"); | |
443 | ||
444 | my $session = $booking->session; | |
445 | ||
446 | $session->{when_at} gt now_datetime | |
447 | or return $class->req_bookinglist($req, "You cannot modify past bookings"); | |
448 | ||
449 | my @options = split /,/, $booking->{options}; | |
450 | local $SIG{__DIE__}; | |
451 | eval { | |
452 | $session->remove_booking($siteuser); | |
453 | }; | |
454 | $@ and return $class->req_cancelbookingconfirm | |
455 | ($req, "Could not remove booking $@"); | |
456 | ||
457 | my $seminar = $session->seminar; | |
458 | ||
459 | my @sem_options = $seminar->option_descs($req->cfg, \@options); | |
460 | ||
461 | require BSE::ComposeMail; | |
462 | my $cfg = $req->cfg; | |
463 | my $it = DevHelp::Tags::Iterate->new; | |
464 | my %acts; | |
465 | %acts = | |
466 | ( | |
467 | BSE::Util::Tags->static(undef, $cfg), | |
468 | user => [ \&tag_hash_plain, $siteuser ], | |
469 | seminar => [ \&tag_hash_plain, $seminar ], | |
470 | session => [ \&tag_hash_plain, $session ], | |
471 | booking => [ \&tag_hash_plain, $booking ], | |
472 | location => [ \&tag_hash_plain, $session->location ], | |
473 | $it->make_iterator(undef, 'option', 'options', \@sem_options), | |
474 | ); | |
475 | ||
476 | my $mailer = BSE::ComposeMail->new(cfg => $cfg); | |
477 | if ($cfg->entry('seminars', 'notify_user_cancel', 1)) { | |
478 | my $email = $cfg->entry('seminar', 'notify_user_cancel_email') | |
479 | || $cfg->entry('shop', 'from', $Constants::SHOP_FROM); | |
480 | my $from = $cfg->entry('shop', 'from', $Constants::SHOP_FROM); | |
481 | my $subject = $cfg->entry('seminar', 'notify_user_cancel_subject', | |
482 | 'A user has cancelled their booking'); | |
483 | unless ($mailer->send(to => $email, | |
484 | subject => $subject, | |
485 | template => 'admin/user_unbook_seminar', | |
486 | acts => \%acts)) { | |
487 | return $class->req_cancelbookingconfirm | |
488 | ($req, "The user booking was cancelled, but there was an error sending the email notification:".$mailer->errstr ); | |
489 | } | |
490 | } | |
491 | my $subject = $cfg->entry('seminars', 'unbooked_notify_subject', | |
492 | 'Seminar booking cancellation confirmation'); | |
493 | unless ($mailer->send(to => $siteuser, | |
494 | subject => $subject, | |
495 | template => 'user/email_unbook_seminar', | |
496 | acts => \%acts)) { | |
497 | return $class->req_cancelbookingconfirm | |
498 | ($req, "The user booking was cancelled, but there was an error sending the email notification:".$mailer->errstr ); | |
499 | } | |
500 | ||
501 | my $r = $cgi->param('r'); | |
502 | unless ($r) { | |
503 | $r = '/cgi-bin/nuser.pl/user/bookinglist'; | |
504 | } | |
505 | $r .= $r =~ /\?/ ? '&' : '?'; | |
506 | $r .= "m=Booking+cancelled"; | |
507 | ||
508 | return BSE::Template->get_refresh($r, $req->cfg); | |
509 | } | |
510 | ||
511 | sub req_editbooking { | |
512 | my ($class, $req, $errors) = @_; | |
513 | ||
514 | my $cgi = $req->cgi; | |
515 | ||
516 | my $id = $cgi->param('id'); | |
517 | defined $id && $id =~ /^\d+$/ | |
518 | or return $class->req_bookinglist($req, "id parameter invalid"); | |
519 | ||
520 | my $siteuser = $req->siteuser; | |
521 | ||
522 | require BSE::TB::SeminarBookings; | |
523 | my $booking = BSE::TB::SeminarBookings->getByPkey($id); | |
524 | ||
525 | $booking && $booking->{siteuser_id} == $siteuser->{id} | |
526 | or return $class->req_bookinglist($req, "booking $id not found"); | |
527 | ||
528 | my $session = $booking->session; | |
529 | ||
530 | my $now = now_datetime; | |
531 | $session->{when_at} gt $now | |
532 | or return $class->req_bookinglist($req, "You cannot modify past bookings"); | |
533 | ||
534 | my $message = $req->message($errors); | |
535 | ||
536 | my $seminar = $session->seminar; | |
537 | my @sem_options = | |
538 | $seminar->option_descs($req->cfg, [ split /,/, $booking->{options} ]); | |
539 | my @unbooked = $seminar->get_unbooked_by_user($siteuser); | |
540 | @unbooked = | |
541 | sort { $b->{when_at} cmp $a->{when_at} } | |
542 | grep $_->{when_at} gt $now, ( @unbooked, $session ); | |
543 | ||
544 | my $current_option; | |
545 | my $it = BSE::Util::Iterate->new; | |
546 | my %acts; | |
547 | %acts = | |
548 | ( | |
549 | $req->dyn_user_tags(), | |
550 | session => [ \&tag_hash, $session ], | |
551 | seminar => [ \&tag_hash, $seminar ], | |
552 | location => [ \&tag_hash, $session->location ], | |
553 | booking => [ \&tag_hash, $booking ], | |
554 | message => escape_html($message), | |
555 | error_img => [ \&tag_error_img, $req->cfg, $errors ], | |
556 | $it->make_iterator(undef, 'option', 'options', \@sem_options, | |
557 | undef, undef, \$current_option), | |
558 | option_popup => [ \&tag_option_popup, $req->cgi, \$current_option ], | |
559 | $it->make_iterator(undef, 'isession', 'sessions', \@unbooked), | |
560 | session_popup => | |
561 | [ \&tag_session_popup, $req->cfg, $booking, $req->cgi, \@unbooked ], | |
562 | ); | |
563 | ||
564 | return $req->dyn_response('user/editbooking', \%acts); | |
565 | } | |
566 | ||
567 | sub req_savebooking { | |
568 | my ($self, $req, $message) = @_; | |
569 | ||
570 | my $cgi = $req->cgi; | |
571 | ||
572 | my $id = $cgi->param('id'); | |
573 | defined $id && $id =~ /^\d+$/ | |
574 | or return $self->req_bookinglist($req, "id parameter invalid"); | |
575 | ||
576 | my $siteuser = $req->siteuser; | |
577 | ||
578 | require BSE::TB::SeminarBookings; | |
579 | my $booking = BSE::TB::SeminarBookings->getByPkey($id); | |
580 | $booking && $booking->{siteuser_id} == $siteuser->{id} | |
581 | or return $self->req_bookinglist($req, "booking $id not found"); | |
582 | ||
583 | my $old_session = $booking->session; | |
584 | $old_session->{when_at} gt now_datetime | |
585 | or return $self->req_bookinglist($req, "You cannot modify past bookings"); | |
586 | ||
587 | my @cols = qw/customer_instructions/; | |
588 | for my $name (@cols) { | |
589 | my $value = $cgi->param($name); | |
590 | defined $value and $booking->set($name => $value); | |
591 | } | |
592 | my %errors; | |
593 | my $session_id = $cgi->param('session_id'); | |
594 | if (defined $session_id && $session_id != $booking->{session_id}) { | |
595 | my $new_session = BSE::TB::SeminarSessions->getByPkey($session_id); | |
596 | if ($old_session->{seminar_id} != $new_session->{seminar_id}) { | |
597 | $errors{session_id} = "Invalid session"; | |
598 | } | |
599 | elsif ($new_session->{when_at} lt now_datetime) { | |
600 | $errors{session_id} = "That session is now in the past, sorry"; | |
601 | } | |
602 | else { | |
603 | $booking->{session_id} = $new_session->{id}; | |
604 | } | |
605 | } | |
606 | keys %errors | |
607 | and return $self->req_editbooking($req, \%errors); | |
608 | ||
609 | my $seminar = $booking->session->seminar; | |
610 | my @options; | |
611 | for my $name (split /,/, $seminar->{options}) { | |
612 | push @options, ($cgi->param($name))[0]; | |
613 | } | |
614 | $booking->{options} = join ',', @options; | |
615 | ||
616 | eval { | |
617 | $booking->save; | |
618 | }; | |
619 | $@ | |
620 | and return $self->req_editbooking($req, { error => $@ }); | |
621 | ||
622 | my @sem_options = $seminar->option_descs($req->cfg, \@options); | |
623 | ||
624 | my $session = $booking->session; | |
625 | require BSE::ComposeMail; | |
626 | my $cfg = $req->cfg; | |
627 | my $mailer = BSE::ComposeMail->new(cfg => $cfg); | |
628 | my $it = DevHelp::Tags::Iterate->new; | |
629 | my %acts; | |
630 | %acts = | |
631 | ( | |
632 | BSE::Util::Tags->static(undef, $cfg), | |
633 | user => [ \&tag_hash_plain, $siteuser ], | |
634 | seminar => [ \&tag_hash_plain, $seminar ], | |
635 | session => [ \&tag_hash_plain, $session ], | |
636 | booking => [ \&tag_hash_plain, $booking ], | |
637 | location => [ \&tag_hash_plain, $session->location ], | |
638 | $it->make_iterator(undef, 'option', 'options', \@sem_options), | |
639 | ); | |
640 | ||
641 | if ($cfg->entry('seminars', 'notify_user_edit', 1)) { | |
642 | my $email = $cfg->entry('seminar', 'notify_user_edit_email') | |
643 | || $cfg->entry('shop', 'from', $Constants::SHOP_FROM); | |
644 | my $subject = $cfg->entry('seminar', 'notify_user_edit_subject', | |
645 | 'A user has edited their booking'); | |
646 | unless ($mailer->send(to => $email, | |
647 | subject => $subject, | |
648 | template => 'admin/user_edit_seminar', | |
649 | acts => \%acts)) { | |
650 | return $self->req_editbooking | |
651 | ($req, "Your booking was changed, but there was an error sending the email notification:".$mailer->errstr ); | |
652 | } | |
653 | } | |
654 | ||
655 | my $subject = $cfg->entry('seminars', 'edit_notify_subject', | |
656 | 'Your seminar booking has been changed'); | |
657 | unless ($mailer->send(to => $siteuser, | |
658 | subject => $subject, | |
659 | template => 'user/email_edit_seminar', | |
660 | acts => \%acts)) { | |
661 | return $self->req_editbooking | |
662 | ($req, _email => "Your booking was changed, but there was an error sending the email notification:".$mailer->errstr ); | |
663 | } | |
664 | ||
665 | my $r = $cgi->param('r'); | |
666 | unless ($r) { | |
667 | $r = '/cgi-bin/nuser.pl/user/bookinglist' | |
668 | } | |
669 | $r .= $r =~ /\?/ ? '&' : '?'; | |
670 | $r .= "m=Booking+updated"; | |
671 | ||
672 | return BSE::Template->get_refresh($r, $req->cfg); | |
673 | } | |
674 | ||
0eb78304 TC |
675 | sub check_action { |
676 | my ($self, $req, $action, $rresult) = @_; | |
677 | ||
678 | unless ($req->siteuser) { | |
679 | my %logon_params; | |
680 | if ($ENV{REQUEST_METHOD} eq 'GET') { | |
681 | my @params = | |
682 | ( | |
683 | "a_$action" => 1, | |
684 | _p => $self->controller_id, | |
685 | ); | |
686 | my $cgi = $req->cgi; | |
687 | for my $name ($cgi->param) { | |
688 | my @values = $cgi->param($name); | |
689 | push @params, $name => $_ for @values; | |
690 | } | |
691 | my @param_args; | |
692 | while (@params) { | |
693 | my ($name, $value) = splice @params, 0, 2; | |
694 | push @param_args, $name . '=' . escape_uri($value); | |
695 | } | |
696 | my $r = $ENV{SCRIPT_NAME} . '?' . join '&', @param_args; | |
697 | $logon_params{r} = $r; | |
698 | } | |
699 | $logon_params{message} = | |
700 | $req->text('needlogongen', "You need to logon to use this function"); | |
701 | $logon_params{show_logon} = 1; | |
702 | my $logon = '/cgi-bin/user.pl?' . join '&', | |
703 | map { $_ . '=' . escape_uri($logon_params{$_}) } keys %logon_params; | |
704 | $$rresult = BSE::Template->get_refresh($logon, $req->cfg); | |
705 | return; | |
706 | } | |
707 | ||
708 | return 1; | |
709 | } | |
710 | ||
3fb296b8 TC |
711 | sub tag_option_popup { |
712 | my ($cgi, $roption) = @_; | |
713 | ||
714 | $$roption | |
715 | or return '** popup_option not in options iterator **'; | |
716 | ||
717 | my $option = $$roption; | |
718 | ||
719 | my @extras; | |
720 | my $value = $cgi->param($option->{id}); | |
721 | defined $value or $value = $option->{value}; | |
722 | if ($value) { | |
723 | push @extras, -default => $value; | |
724 | } | |
725 | ||
726 | return popup_menu(-name => $option->{id}, | |
727 | -values => $option->{values}, | |
728 | -labels => $option->{labels}, | |
729 | @extras); | |
730 | } | |
731 | ||
732 | sub tag_session_popup { | |
733 | my ($cfg, $booking, $cgi, $unbooked) = @_; | |
734 | ||
735 | my $default = $cgi->param('session_id'); | |
736 | defined $default or $default = $booking->{session_id}; | |
737 | my %locations; | |
738 | for my $session (@$unbooked) { | |
739 | unless ($locations{$session->{location_id}}) { | |
740 | $locations{$session->{location_id}} = $session->location; | |
741 | } | |
742 | } | |
743 | ||
744 | my $date_fmt = $cfg->entry('seminars', 'popup_date_format', | |
745 | "%I:%M %p %d %b %Y"); | |
746 | return popup_menu | |
747 | (-name => 'session_id', | |
748 | -values => [ map $_->{id}, @$unbooked ], | |
749 | -labels => | |
750 | { map | |
751 | { $_->{id} => | |
752 | _session_desc($_, $locations{$_->{location_id}}, $date_fmt) | |
753 | } @$unbooked | |
754 | }, | |
755 | -default => $default); | |
756 | } | |
757 | ||
758 | sub _session_desc { | |
759 | my ($session, $location, $date_fmt) = @_; | |
760 | ||
761 | $location->{description} . ' ' . | |
762 | dh_strftime_sql_datetime($date_fmt, $session->{when_at}); | |
763 | } | |
764 | ||
f5505b76 TC |
765 | sub _refresh_wishlist { |
766 | my ($self, $req, $msg) = @_; | |
767 | ||
768 | my $url = $req->cgi->param('r'); | |
3624a308 | 769 | print STDERR "url $url\n" if $url; |
f5505b76 TC |
770 | unless ($url) { |
771 | $url = $req->user_url(nuser => userpage => _t => 'wishlist'); | |
772 | } | |
773 | ||
774 | if ($url eq 'ajaxwishlist') { | |
775 | return $self->req_info($req, $msg); | |
776 | } | |
777 | else { | |
778 | $req->flash($msg); | |
779 | return BSE::Template->get_refresh($url, $req->cfg); | |
780 | } | |
781 | } | |
782 | ||
783 | sub _wishlist_product { | |
784 | my ($self, $req, $rresult) = @_; | |
785 | ||
786 | my $product_id = $req->cgi->param('product_id'); | |
787 | unless (defined $product_id && $product_id =~ /^\d+$/) { | |
788 | $$rresult = $self->req_userpage($req, "Missing or invalid product id"); | |
789 | return; | |
790 | } | |
791 | require Products; | |
792 | my $product = Products->getByPkey($product_id); | |
793 | unless ($product) { | |
794 | $$rresult = $self->req_userpage($req, "Unknown product id"); | |
795 | return; | |
796 | } | |
797 | ||
798 | return $product; | |
799 | } | |
800 | ||
801 | sub req_wishlistadd { | |
802 | my ($self, $req) = @_; | |
803 | ||
804 | my $user = $req->siteuser; | |
805 | ||
806 | my $result; | |
807 | my $product = $self->_wishlist_product($req, \$result) | |
808 | or return $result; | |
809 | if ($user->product_in_wishlist($product)) { | |
810 | return $self->_refresh_wishlist($req, "Product $product->{title} is already in your wishlist"); | |
811 | } | |
812 | ||
813 | eval { | |
814 | local $SIG{__DIE__}; | |
815 | $user->add_to_wishlist($product); | |
816 | }; | |
817 | $@ | |
818 | and return $self->_refresh_wishlist($req, $@); | |
819 | ||
820 | return $self->_refresh_wishlist($req, "Product $product->{title} added to your wishlist"); | |
821 | } | |
822 | ||
823 | sub req_wishlistdel { | |
824 | my ($self, $req) = @_; | |
825 | ||
826 | my $user = $req->siteuser; | |
827 | ||
828 | my $result; | |
829 | my $product = $self->_wishlist_product($req, \$result) | |
830 | or return $result; | |
831 | ||
832 | unless ($user->product_in_wishlist($product)) { | |
833 | return $self->_refresh_wishlist($req, "Product $product->{title} is not in your wishlist"); | |
834 | } | |
835 | ||
836 | eval { | |
837 | local $SIG{__DIE__}; | |
838 | $user->remove_from_wishlist($product); | |
839 | }; | |
840 | $@ | |
841 | and return $self->_refresh_wishlist($req, $@); | |
842 | ||
843 | return $self->_refresh_wishlist($req, "Product $product->{title} removed from your wishlist"); | |
844 | } | |
845 | ||
846 | sub _wishlist_move { | |
847 | my ($self, $req, $method) = @_; | |
848 | ||
849 | my $user = $req->siteuser; | |
850 | ||
851 | my $result; | |
852 | my $product = $self->_wishlist_product($req, \$result) | |
853 | or return $result; | |
854 | ||
855 | unless ($user->product_in_wishlist($product)) { | |
856 | return $self->_refresh_wishlist($req, "Product $product->{title} is not in your wishlist"); | |
857 | } | |
858 | ||
859 | eval { | |
860 | local $SIG{__DIE__}; | |
861 | $user->$method($product); | |
862 | }; | |
863 | $@ | |
864 | and return $self->_refresh_wishlist($req, $@); | |
865 | ||
866 | return $self->_refresh_wishlist($req); | |
867 | } | |
868 | ||
869 | sub req_wishlisttop { | |
870 | my ($self, $req) = @_; | |
871 | ||
872 | return $self->_wishlist_move($req, 'move_to_wishlist_top'); | |
873 | } | |
874 | ||
875 | sub req_wishlistbottom { | |
876 | my ($self, $req) = @_; | |
877 | ||
878 | return $self->_wishlist_move($req, 'move_to_wishlist_bottom'); | |
879 | } | |
880 | ||
881 | sub req_wishlistup { | |
882 | my ($self, $req) = @_; | |
883 | ||
884 | return $self->_wishlist_move($req, 'move_up_wishlist'); | |
885 | } | |
886 | ||
887 | sub req_wishlistdown { | |
888 | my ($self, $req) = @_; | |
889 | ||
890 | return $self->_wishlist_move($req, 'move_down_wishlist'); | |
891 | } | |
3fb296b8 | 892 | |
0eb78304 | 893 | 1; |