PageRenderTime 63ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/tcl/gc-defs.tcl

https://github.com/MikeSisk/ArsDigita-Community-System-3.2.3
TCL | 580 lines | 493 code | 58 blank | 29 comment | 60 complexity | 6e1b3e909534b4dfbd9af20ee207ed99 MD5 | raw file
  1. # $Id: gc-defs.tcl,v 3.1.2.2 2000/03/15 19:00:12 curtisg Exp $
  2. #
  3. # gc-defs.tcl
  4. #
  5. # by philg@mit.edu back in the Jurassic period (1996?)
  6. #
  7. # definitions for the classified ads system
  8. util_report_library_entry
  9. proc gc_system_name {} {
  10. set default "[ad_system_name] Classifieds"
  11. return [ad_parameter SystemName gc $default]
  12. }
  13. proc gc_system_url {} {
  14. return "[ad_url][ad_parameter PartialUrlStub gc "/gc/"]"
  15. }
  16. proc gc_system_owner {} {
  17. return [ad_parameter SystemOwner gc [ad_system_owner]]
  18. }
  19. proc gc_header {page_title} {
  20. return [ad_header $page_title]
  21. }
  22. proc gc_footer {signatory} {
  23. return "<hr>
  24. <a href=\"mailto:$signatory\"><address>$signatory</address></a>
  25. </body>
  26. </html>
  27. "
  28. }
  29. proc gc_search_active_p {} {
  30. return [ad_parameter ProvideLocalSearchP gc 0]
  31. }
  32. proc gc_query_for_domain_info {domain_id {extra_columns ""}} {
  33. return "select domain, full_noun, domain_type, auction_p, geocentric_p, wtb_common_p, primary_maintainer_id, $extra_columns users.email as maintainer_email
  34. from ad_domains, users
  35. where domain_id = $domain_id
  36. and primary_maintainer_id = users.user_id"
  37. }
  38. proc gc_db_gethandle {} {
  39. return [ns_db gethandle]
  40. }
  41. # cache the grouping stuff for the cover page
  42. proc gc_categories_for_one_domain {domain_id} {
  43. set db [ns_db gethandle subquery]
  44. set selection [ns_db select $db "select count(*) as count,primary_category as category
  45. from classified_ads
  46. where domain_id = $domain_id
  47. and (sysdate <= expires or expires is null)
  48. group by primary_category
  49. order by upper(primary_category)"]
  50. while {[ns_db getrow $db $selection]} {
  51. set_variables_after_query
  52. set url "view-category.tcl?domai_idn=[ns_urlencode $domain_id]&primary_category=[ns_urlencode $category]"
  53. if { $count == 1 } {
  54. set pretty_count "1 Ad"
  55. } else {
  56. set pretty_count "$count Ads"
  57. }
  58. append result "<li><a href=\"$url\">$category</a> ($pretty_count)"
  59. }
  60. if { ![info exists result] } {
  61. return "No ads found; probably they've all expired."
  62. } else {
  63. return $result
  64. }
  65. }
  66. # audit insert
  67. proc gc_audit_insert {classified_ad_id {deleted_by_admin_p 0}} {
  68. if $deleted_by_admin_p {
  69. set admin_column ",\ndeleted_by_admin_p"
  70. set admin_value ",\n 't'"
  71. } else {
  72. set admin_column ""
  73. set admin_value ""
  74. }
  75. return "insert into classified_ads_audit
  76. (classified_ad_id,
  77. user_id,
  78. domain_id,
  79. originating_ip,
  80. posted,
  81. expires,
  82. wanted_p,
  83. private_p,
  84. primary_category,
  85. subcategory_1,
  86. subcategory_2,
  87. manufacturer,
  88. model,
  89. one_line,
  90. full_ad,
  91. html_p,
  92. last_modified,
  93. audit_ip$admin_column)
  94. select
  95. classified_ad_id,
  96. user_id,
  97. domain_id,
  98. originating_ip,
  99. posted,
  100. expires,
  101. wanted_p,
  102. private_p,
  103. primary_category,
  104. subcategory_1,
  105. subcategory_2,
  106. manufacturer,
  107. model,
  108. one_line,
  109. full_ad,
  110. html_p,
  111. last_modified,
  112. '[DoubleApos [ns_conn peeraddr]]'$admin_value
  113. from classified_ads where classified_ad_id = $classified_ad_id"
  114. }
  115. # spamming system
  116. proc gc_PrettyFrequency {frequency} {
  117. if { $frequency == "daily" } {
  118. return "Daily"
  119. } elseif { $frequency == "weekly" } {
  120. return "Weekly"
  121. } elseif { $frequency == "monthu" } {
  122. return "Monday/Thursday"
  123. } elseif { $frequency == "instant" } {
  124. return "Instantly"
  125. } else { error "Unrecognized frequency: $frequency" }
  126. }
  127. proc gc_spam {frequency} {
  128. set db_conns [ns_db gethandle subquery 2]
  129. set db [lindex $db_conns 0]
  130. set db_sub [lindex $db_conns 1]
  131. # we could just update classified_email_alerts_last_updates
  132. # right now but we don't because we might get interrupted
  133. set start_time [database_to_tcl_string $db "select to_char(sysdate,'YYYY-MM-DD HH24:MI:SS') from dual"]
  134. ns_log Notice "GC started spamming $frequency at $start_time.\n\n"
  135. set last_time [database_to_tcl_string $db "select unique to_char($frequency,'YYYY-MM-DD HH24:MI:SS') from classified_alerts_last_updates"]
  136. set selection [ns_db select $db "select classified_email_alerts.*, classified_email_alerts.alert_id, users_alertable.email
  137. from classified_email_alerts, users_alertable
  138. where users_alertable.user_id = classified_email_alerts.user_id
  139. and valid_p = 't'
  140. and frequency = '$frequency'
  141. and sysdate <= expires"]
  142. set mail_counter 0
  143. while {[ns_db getrow $db $selection]} {
  144. # this is the outer loop where each row is an alert for one email address
  145. set_variables_after_query
  146. if { $alert_type == "all" } {
  147. # the query is simple
  148. set query "select classified_ads.*, users.email as poster_email
  149. from classified_ads, users
  150. where classified_ads.user_id=users.user_id
  151. and domain_id = $domain_id
  152. and (expires > sysdate or expires is NULL)
  153. and (last_modified > to_date('$last_time','YYYY-MM-DD HH24:MI:SS'))
  154. order by classified_ad_id desc"
  155. } elseif { $alert_type == "category" } {
  156. set query "select classified_ads.*, users.email as poster_email
  157. from classified_ads, users
  158. where classified_ads.user_id = users.user_id
  159. and domain_id = $domain_id
  160. and primary_category = '[DoubleApos $category]'
  161. and (expires > sysdate or expires is NULL)
  162. and (last_modified > to_date('$last_time','YYYY-MM-DD HH24:MI:SS'))
  163. order by classified_ad_id desc"
  164. } elseif { $alert_type == "keywords"} {
  165. set query "select classified_ads.*, users.email as poster_email
  166. from classified_ads, users
  167. where classified_ads.user_id = users.user_id
  168. and domain_id = $domain_id
  169. and pseudo_contains(users.first_names || users.last_name || users.email || one_line || full_ad, '[DoubleApos $keywords]') > 0
  170. and (expires > sysdate or expires is NULL)
  171. and (last_modified > to_date('$last_time','YYYY-MM-DD HH24:MI:SS'))
  172. order by classified_ad_id desc"
  173. }
  174. set n_rows 0
  175. set error_p 0
  176. set msg_body ""
  177. set id_list ""
  178. if [catch {set sub_selection [ns_db select $db_sub "$query"]} errmsg] {
  179. set msg_body "Your query resulted in an error. Here's the SQL:\n\n$query\n\nHere's the error:\n\n$errmsg\n
  180. This should never have happened because you formulated your query with
  181. my form. A copy of this message has gone to me (philg@mit.edu) and
  182. I'll keep trying to fix it. If this is irritating you, you can come
  183. back to [gc_system_name] at [gc_system_url] and remove this alert."
  184. catch { ns_sendmail [ad_host_administrator] [ad_host_administrator] "error in classifieds spam" "$errmsg"}
  185. set recipients "$email"
  186. set error_p 1
  187. } else {
  188. # no error from the database
  189. set recipients $email
  190. while {[ns_db getrow $db_sub $sub_selection]} {
  191. # this is the inner loop where each row
  192. # is an ad that corresponds to an alert
  193. set_variables_after_subquery
  194. incr n_rows
  195. lappend id_list $classified_ad_id
  196. if { $howmuch == "everything" } {
  197. # user wants the whole ad
  198. append msg_body "--------------- Ad $classified_ad_id from $poster_email\n\n"
  199. append msg_body "Subject: $one_line\n\n"
  200. append msg_body "[ns_striphtml $full_ad]\n\n"
  201. } else {
  202. # user only wants one line/ad
  203. append msg_body "$one_line ($classified_ad_id, $poster_email)\n"
  204. }
  205. }
  206. }
  207. if { $msg_body != "" } {
  208. # we have something to send
  209. if { $error_p == 0 } {
  210. # there was no error, so let's add a little something...
  211. # turn spaces into %20's
  212. set id_list_for_url [ns_urlencode $id_list]
  213. append msg_body "\nIf you love the Web and want to check out a Web page
  214. of these ads, just cut and paste the following URL:
  215. [gc_system_url]alert-summary.tcl?id_list=$id_list_for_url
  216. I hope you enjoy this service of [gc_system_name], which you'll find at
  217. [gc_system_url]
  218. Yours,
  219. a little bit of NaviServer Tcl API and SQL code
  220. Note: if you really are annoyed by this message then just enter the
  221. following URL into a browser and you'll disable the alert that
  222. generated this mail:
  223. [gc_system_url]alert-disable.tcl?alert_id=[ns_urlencode $alert_id]
  224. "
  225. }
  226. if [catch { ns_sendmail $recipients [gc_system_owner] "Recent ads from [gc_system_name]" $msg_body } errmsg] {
  227. ns_log Notice "error sending gc_spam to \"$recipients\" $errmsg"
  228. } else {
  229. ns_log Notice "Sent mail to $recipients.\n"
  230. incr mail_counter
  231. }
  232. }
  233. }
  234. # we're done with all the alerts
  235. ns_db dml $db "update classified_alerts_last_updates
  236. set $frequency = to_date('$start_time','YYYY-MM-DD HH24:MI:SS'),
  237. $frequency\_total = $frequency\_total + $mail_counter"
  238. ns_log Notice "\nGC AlertSpam completed for $frequency; $mail_counter msgs sent."
  239. }
  240. proc gc_spam_daily {} {
  241. gc_spam daily
  242. }
  243. proc gc_spam_monthu {} {
  244. gc_spam monthu
  245. }
  246. proc gc_spam_weekly {} {
  247. gc_spam weekly
  248. }
  249. proc gc_ad_owner_spam {} {
  250. set db [gc_db_gethandle]
  251. set db_sub [ns_db gethandle subquery]
  252. ns_log Notice "Starting classfieds gc_ad_owner_spam at [ns_localsqltimestamp]"
  253. set generic_preamble "
  254. In the interests of having a well-groomed classified ad system for
  255. everyone, we're sending you this robotically generated message to
  256. remind you to
  257. 1) delete ads for items that have sold
  258. 2) consider updating the price on items that haven't sold
  259. 3) delete duplicate ads
  260. It is effort like this on the part of the users that makes it possible
  261. to offer this service for free.
  262. Here are the ads you've placed to date:
  263. "
  264. set generic_postamble "
  265. Thank you for using [gc_system_name]
  266. (at [gc_system_url]).
  267. "
  268. set selection [ns_db select $db "select max(classified_ads.user_id) as user_id, max(domain_id) as domain_id, max(last_modified) as most_recent_visit, min(last_modified) as least_recent_visit, count(classified_ads.user_id) as n_ads
  269. from classified_ads
  270. where (sysdate <= expires or expires is null)
  271. and (wanted_p <> 't' or sysdate > (last_modified + 30))
  272. and sysdate > last_modified + 6
  273. group by user_id"]
  274. while { [ns_db getrow $db $selection] } {
  275. set_variables_after_query
  276. set sub_selection [ns_db select $db_sub "select classified_ad_id, posted, last_modified, one_line, expired_p(expires) as expired_p, users.email
  277. from classified_ads, users
  278. where classified_ads.user_id = users.user_id
  279. and classified_ads.user_id = $user_id
  280. order by expired_p, classified_ad_id desc"]
  281. if { $n_ads == 1 } {
  282. set subject_line "your ad in [gc_system_name]"
  283. } else {
  284. set subject_line "your $n_ads ads in [gc_system_name]"
  285. }
  286. set body $generic_preamble
  287. set expired_section_started_yet_p 0
  288. while { [ns_db getrow $db_sub $sub_selection] } {
  289. set_variables_after_subquery
  290. if { $last_modified == $posted || $last_modified == "" } {
  291. set modified_phrase ""
  292. } else {
  293. set modified_phrase "(modified $last_modified)"
  294. }
  295. if { $expired_p == "t" } {
  296. if { !$expired_section_started_yet_p } {
  297. append body "\n -- expired ads -- \n\n"
  298. set expired_section_started_yet_p 1
  299. }
  300. set expired_phrase "(EXPIRED)"
  301. } else {
  302. set expired_phrase ""
  303. }
  304. append body "${posted}${expired_phrase} : $one_line $modified_phrase
  305. [gc_system_url]edit-ad-3.tcl?classified_ad_id=$classified_ad_id
  306. "
  307. }
  308. if { $expired_p == "t" } {
  309. # there was at least one expired ad
  310. append body "\n\nNote: you can revive an expired ad by going to the edit URL (above)
  311. and changing the expiration date."
  312. }
  313. append body $generic_postamble
  314. if [catch { [ns_sendmail $email [gc_system_owner] $subject_line $body] } errmsg] {
  315. ns_log Notice "error sending gc_owner_spam to \"$email\""
  316. }
  317. }
  318. ns_log Notice "finished gc_owner_spam at [ns_localsqltimestamp]"
  319. }
  320. # AOLserver stupidly does not source private Tcl after shared Tcl
  321. # probably fixed in 2.3 released
  322. ns_share -init {set gc_spam_scheduled_p 0} gc_spam_scheduled_p
  323. if { !$gc_spam_scheduled_p && ![philg_development_p]} {
  324. ns_log Notice "scheduling classified ad spam"
  325. set gc_spam_scheduled_p 1
  326. if [ad_parameter ProvideEmailAlerts gc 1] {
  327. # 5:10 am every day
  328. ns_schedule_daily 5 10 gc_spam_daily
  329. # we schedule this at 6:10 am twice because
  330. # the AOLserver API isn't powerful enough
  331. # to say "monday AND thursday"
  332. ns_schedule_weekly 1 6 10 gc_spam_monthu
  333. ns_schedule_weekly 4 6 10 gc_spam_monthu
  334. # 7:10 am on Sundays
  335. ns_schedule_weekly 1 7 10 gc_spam_weekly
  336. }
  337. if [ad_parameter NagAdOwners gc 1] {
  338. # 7:10 am on Wednesdays
  339. ns_schedule_weekly 3 7 10 gc_ad_owner_spam
  340. }
  341. }
  342. proc gc_submenu {{domain ""}} {
  343. if {$domain == ""} {
  344. return ""
  345. } else {
  346. set db_sub [ns_db gethandle subquery]
  347. set sub_selection [ns_db 0or1row $db "select domain_id from ad_domains where domain = '[DoubleApos $domain]'"]
  348. if {$sub_selection == ""} {
  349. ns_db releasehandle $db_sub
  350. return ""
  351. }
  352. set_variables_after_subquery
  353. ns_db releasehandle $db_sub
  354. set return_string ""
  355. upvar auction_p auction_p
  356. append return_string "
  357. <form name=jobs_submenu ACTION=/redir.tcl>
  358. <select name=\"url\" onchange=\"go_to_url(this.options\[this.selectedIndex\].value)\">
  359. <OPTION VALUE=\"/gc/domain-top.tcl?domain_id=[ns_urlencode $domain_id]\">Jobs Options
  360. <OPTION VALUE=\"/gc/place-ad.tcl?domain_id=[ns_urlencode $domain_id]\">Place An Ad
  361. <OPTION VALUE=\"/gc/edit-ad.tcl?domain_id=[ns_urlencode $domain_id]\">Edit Old Ad
  362. <OPTION VALUE=\"/gc/add-alert.tcl?domain_id=[ns_urlencode $domain_id]\">Add/Edit Alert\n"
  363. if { [info exists auction_p] && $auction_p == "t" } {
  364. append return_string "<OPTION VALUE=\"/gc/auction-hot.tcl?domain_id=[ns_urlencode $domain_id]\">Hot Auctions\n"
  365. }
  366. set headers [ns_conn headers]
  367. set cookie [ns_set get $headers Cookie]
  368. # parse out the second_to_last_visit date from the cookie
  369. if { [regexp {~second_to_last-([^;]+)} $cookie match second_to_last_visit] } {
  370. append return_string " <OPTION VALUE=\"/gc/new-since-last-visit.tcl?domain_id=[ns_urlencode $domain_id]\">Ads Since Last Visit\n"
  371. }
  372. append return_string "</select>
  373. <noscript><input type=\"Submit\" value=\"GO\"></noscript>
  374. </form>\n"
  375. return $return_string
  376. }
  377. }
  378. proc gc_search_result_string {} {
  379. return "Job listings"
  380. }
  381. ##################################################################
  382. #
  383. # interface to the ad-new-stuff.tcl system
  384. ns_share ad_new_stuff_module_list
  385. if { ![info exists ad_new_stuff_module_list] || [lsearch -glob $ad_new_stuff_module_list "[gc_system_name]*"] == -1 } {
  386. lappend ad_new_stuff_module_list [list [gc_system_name] gc_new_stuff]
  387. }
  388. proc gc_new_stuff {db since_when only_from_new_users_p purpose} {
  389. if { $only_from_new_users_p == "t" } {
  390. set query "select ca.domain_id, ad.domain, count(*) as n_ads
  391. from classified_ads ca, ad_domains ad, users_new
  392. where posted > '$since_when'
  393. and ca.user_id = users_new.user_id
  394. and ad.domain_id = ca.domain_id
  395. group by ca.domain_id, ad.domain"
  396. } else {
  397. set query "select ca.domain_id, ad.domain, count(*) as n_ads
  398. from classified_ads ca, ad_domains ad
  399. where posted > '$since_when'
  400. and ad.domain_id = ca.domain_id
  401. group by ca.domain_id, ad.domain"
  402. }
  403. set result_items ""
  404. set url_stub [ad_parameter PartialUrlStub gc "/gc/"]
  405. set selection [ns_db select $db $query]
  406. while { [ns_db getrow $db $selection] } {
  407. set_variables_after_query
  408. switch $purpose {
  409. web_display {
  410. append result_items "<li><a href=\"${url_stub}domain-top.tcl?[export_url_vars domain_id]\">$domain</a> ($n_ads new ads)\n"
  411. }
  412. site_admin {
  413. append result_items "<li><a href=\"/admin/gc/domain-top.tcl?[export_url_vars domain_id]\">$domain</a> ($n_ads new ads)\n"
  414. }
  415. email_summary {
  416. append result_items "$domain classifieds : $n_ads new ads
  417. -- [ad_url]${url_stub}domain-top.tcl?[export_url_vars domain_id]
  418. "
  419. }
  420. }
  421. }
  422. # we have the result_items or not
  423. if { $purpose == "email_summary" } {
  424. return $result_items
  425. } elseif { ![empty_string_p $result_items] } {
  426. return "<ul>\n\n$result_items\n</ul>\n"
  427. } else {
  428. return ""
  429. }
  430. }
  431. ##################################################################
  432. #
  433. # interface to the ad-user-contributions-summary.tcl system
  434. #
  435. ns_share ad_user_contributions_summary_proc_list
  436. if { ![info exists ad_user_contributions_summary_proc_list] || [util_search_list_of_lists $ad_user_contributions_summary_proc_list "Classified Ads" 0] == -1 } {
  437. lappend ad_user_contributions_summary_proc_list [list "Classified Ads" gc_user_contributions 0]
  438. }
  439. proc_doc gc_user_contributions {db user_id purpose} {Returns list items, one for each classified posting} {
  440. # we query out both the current and audit rows at once (so that we get a complete
  441. # chronology). For an ad that is current but has an audit row as well, we'll
  442. # get the current one first
  443. set selection [ns_db select $db "select classified_ad_id, posted, expired_p(expires) as expired_p, one_line, 'f' as audit_row_p
  444. from classified_ads
  445. where user_id = $user_id
  446. union
  447. select classified_ad_id, posted, 'f' as expired_p, one_line, 't' as audit_row_p
  448. from classified_ads_audit
  449. where user_id = $user_id
  450. order by classified_ad_id, audit_row_p"]
  451. set classified_items ""
  452. set last_id ""
  453. while {[ns_db getrow $db $selection]} {
  454. set_variables_after_query
  455. if { $classified_ad_id == $last_id } {
  456. # this is an audit row for a current ad; skip printing it
  457. continue
  458. }
  459. set suffix ""
  460. if {$expired_p == "t"} {
  461. set suffix "<font color=red>expired</font>\n"
  462. }
  463. if {$audit_row_p == "t" } {
  464. set suffix "<font color=red>deleted</font>\n"
  465. set target_url "view-ad-history.tcl"
  466. } else {
  467. # regular ad
  468. set target_url "view-one.tcl"
  469. if { $purpose == "site_admin" && $expired_p != "t" } {
  470. append suffix "\[<a target=another_window href=\"/admin/gc/edit-ad.tcl?classified_ad_id=$classified_ad_id\">Edit</a> |
  471. <a target=another_window href=\"/admin/gc/delete-ad.tcl?classified_ad_id=$classified_ad_id\">Delete</a> \]\n"
  472. }
  473. }
  474. append classified_items "<li>[util_AnsiDatetoPrettyDate $posted]: <A HREF=\"/gc/$target_url?classified_ad_id=$classified_ad_id\">$one_line</a> $suffix\n"
  475. set last_id $classified_ad_id
  476. }
  477. if [empty_string_p $classified_items] {
  478. return [list]
  479. } else {
  480. return [list 0 "Classified Ads" "<ul>\n\n$classified_items\n\n</ul>\n"]
  481. }
  482. }
  483. proc_doc gc_maybe_set_domain_id {} {For pages to which users have bookmarks with the old 'domain' primary key, derive domain_id from the domain variable set in the form.} {
  484. uplevel {
  485. if {![info exists domain_id] && [info exists domain]} {
  486. set db_sub [ns_db gethandle subquery]
  487. set domain_id [database_to_tcl_string_or_null $db_sub \
  488. "select domain_id from ad_domains
  489. where domain = '[DoubleApos $domain]'"]
  490. ns_db releasehandle $db_sub
  491. }
  492. }
  493. }
  494. util_report_successful_library_load