From f9440deeb6dac3310efa8b1c9322885eea5b4ddf Mon Sep 17 00:00:00 2001 From: Scott Ostler Date: Sun, 7 Nov 2010 14:26:44 -0500 Subject: Fix line ending for dailyimgupload.py --- scripts/dailyimgupload.py | 314 +++++++++++++++++++++++----------------------- 1 file changed, 157 insertions(+), 157 deletions(-) diff --git a/scripts/dailyimgupload.py b/scripts/dailyimgupload.py index 186614d..66f2b7b 100644 --- a/scripts/dailyimgupload.py +++ b/scripts/dailyimgupload.py @@ -1,157 +1,157 @@ -import ctypes -import datetime -import os -import platform -import shutil -import sys -import traceback -import s3upload - - -def freespace(p): - """ - FROM: http://atlee.ca/blog/2008/02/23/getting-free-diskspace-in-python/ - http://stackoverflow.com/questions/51658/cross-platform-space-remaining-on-volume-using-python - Returns the number of free bytes on the drive that ``p`` is on - """ - if platform.system() == 'Windows': - free_bytes = ctypes.c_ulonglong(0) - ctypes.windll.kernel32.GetDiskFreeSpaceExW(ctypes.c_wchar_p(p), None, None, ctypes.pointer(free_bytes)) - return free_bytes.value - else: - s = os.statvfs(p) - return s.f_bsize * s.f_bavail - -def directory_size(path): - """ - FROM: http://stackoverflow.com/questions/1392413/calculating-a-directory-size-using-python - """ - total_size = 0.0 - for dirpath, dirnames, filenames in os.walk(path): - for f in filenames: - fp = os.path.join(dirpath, f) - total_size += os.path.getsize(fp) - return total_size - -def parse_date_dir(d, date_fmt): - if not os.path.exists(d): - raise ValueError('%s does not exist' % d) - if not os.path.isdir(d): - raise ValueError('%s is not a directory' % d) - return datetime.datetime.strptime(os.path.basename(d), date_fmt) - -def is_date_dir(d, date_fmt): - try: - parse_date_dir(d, date_fmt) - return True - except ValueError: - return False - -def get_directory_list(path, date_fmt='%Y%m%d'): - parse_func = lambda d: parse_date_dir(d, date_fmt) - subdirs = [os.path.join(path, child) for child in os.listdir(path)] - datedirs = [d for d in subdirs if is_date_dir(d, date_fmt)] - return sorted(datedirs, key=parse_func) - - -def upload_dirs_until_free(path, target_free_mbs, dryrun): - starting_freespace = float(freespace(path)) - dirs_uploaded = 0 - files_uploaded = 0 - cur_freespace = starting_freespace - reclaimed_space = 0.0 - error = False - directory_list = get_directory_list(path) - - if not directory_list: - print "Target directory %s has no subdirectories!" % path - sys.exit(1) - - print "Target directory: %s" % path - print "Starting freespace: %.02f MBs" % (starting_freespace / 1024 / 1024) - print "Target freespace: %.02f MBs" % target_free_mbs - print "Image subdirectories: %s" % len(directory_list) - - if dryrun: - print - print '!!! Doing dryrun -- current free space will be estimated !!!' - - print - try: - for dir_to_upload in directory_list: - if cur_freespace >= target_free_mbs * 1024 * 1024: - break - - dir_size = directory_size(dir_to_upload) - print 'Uploading %s (%.02f MBs)' % (dir_to_upload, dir_size / 1024 / 1024) - - res = s3upload.do_upload(dir_to_upload, verbose=False, dryrun=dryrun) - files_uploaded += res['files_uploaded'] - print "%s files uploaded in %.02fs" % (res['files_uploaded'], res['sec_elapsed']) - - dirs_uploaded += 1 - reclaimed_space += dir_size - - if not dryrun: - print "Deleting %s" % dir_to_upload - shutil.rmtree(dir_to_upload) - - if dryrun: - cur_freespace += dir_size - else: - cur_freespace = float(freespace(path)) - print "%.02f MBs now free" % (cur_freespace / 1024 / 1024) - print - - except Exception: - print "An unexpected error occured!" - error = True - traceback.print_exc() - - print "---------------------------------------" - if error: - pass - else: - pass - print "Finished successfully" if not error else "!!! Terminated abnormally !!!" - print "Current free space: %.02f MBs" % (cur_freespace / 1024 / 1024) - print "Reclaimed space: %.02f MBs" % (reclaimed_space / 1024 / 1024) - print "Directories uploaded: %s" % dirs_uploaded - print "Files uploaded: %s" % files_uploaded - - -if __name__ == '__main__': - if not 4 <= len(sys.argv) <= 5: - print "usage: dailyimgupload.py workingdir path megabytes [dryrun]" - sys.exit(1) - - wd = sys.argv[1] - if not os.path.isdir(wd): - print "Invalid working directory: %s" % wd - sys.exit(1) - print "Switching working directory to %s" % wd - os.chdir(wd) - - path = sys.argv[2] - if not os.path.isdir(path): - print "invalid image directory: %s" % path - sys.exit(1) - - mbs = sys.argv[3] - try: - target_free_mbs = float(mbs) - except ValueError: - print "invalid number of megabytes: %s" % mbs - sys.exit(1) - - if len(sys.argv) == 5: - dryrun = sys.argv[4] - if dryrun in ('true', 'false'): - dryrun = dryrun == 'true' - else: - print "invalid dry run argument: %s (must be either 'true' or 'false')" % dryrun - sys.exit(1) - else: - dryrun = True - - upload_dirs_until_free(path, target_free_mbs, dryrun) +import ctypes +import datetime +import os +import platform +import shutil +import sys +import traceback +import s3upload + + +def freespace(p): + """ + FROM: http://atlee.ca/blog/2008/02/23/getting-free-diskspace-in-python/ + http://stackoverflow.com/questions/51658/cross-platform-space-remaining-on-volume-using-python + Returns the number of free bytes on the drive that ``p`` is on + """ + if platform.system() == 'Windows': + free_bytes = ctypes.c_ulonglong(0) + ctypes.windll.kernel32.GetDiskFreeSpaceExW(ctypes.c_wchar_p(p), None, None, ctypes.pointer(free_bytes)) + return free_bytes.value + else: + s = os.statvfs(p) + return s.f_bsize * s.f_bavail + +def directory_size(path): + """ + FROM: http://stackoverflow.com/questions/1392413/calculating-a-directory-size-using-python + """ + total_size = 0.0 + for dirpath, dirnames, filenames in os.walk(path): + for f in filenames: + fp = os.path.join(dirpath, f) + total_size += os.path.getsize(fp) + return total_size + +def parse_date_dir(d, date_fmt): + if not os.path.exists(d): + raise ValueError('%s does not exist' % d) + if not os.path.isdir(d): + raise ValueError('%s is not a directory' % d) + return datetime.datetime.strptime(os.path.basename(d), date_fmt) + +def is_date_dir(d, date_fmt): + try: + parse_date_dir(d, date_fmt) + return True + except ValueError: + return False + +def get_directory_list(path, date_fmt='%Y%m%d'): + parse_func = lambda d: parse_date_dir(d, date_fmt) + subdirs = [os.path.join(path, child) for child in os.listdir(path)] + datedirs = [d for d in subdirs if is_date_dir(d, date_fmt)] + return sorted(datedirs, key=parse_func) + + +def upload_dirs_until_free(path, target_free_mbs, dryrun): + starting_freespace = float(freespace(path)) + dirs_uploaded = 0 + files_uploaded = 0 + cur_freespace = starting_freespace + reclaimed_space = 0.0 + error = False + directory_list = get_directory_list(path) + + if not directory_list: + print "Target directory %s has no subdirectories!" % path + sys.exit(1) + + print "Target directory: %s" % path + print "Starting freespace: %.02f MBs" % (starting_freespace / 1024 / 1024) + print "Target freespace: %.02f MBs" % target_free_mbs + print "Image subdirectories: %s" % len(directory_list) + + if dryrun: + print + print '!!! Doing dryrun -- current free space will be estimated !!!' + + print + try: + for dir_to_upload in directory_list: + if cur_freespace >= target_free_mbs * 1024 * 1024: + break + + dir_size = directory_size(dir_to_upload) + print 'Uploading %s (%.02f MBs)' % (dir_to_upload, dir_size / 1024 / 1024) + + res = s3upload.do_upload(dir_to_upload, verbose=False, dryrun=dryrun) + files_uploaded += res['files_uploaded'] + print "%s files uploaded in %.02fs" % (res['files_uploaded'], res['sec_elapsed']) + + dirs_uploaded += 1 + reclaimed_space += dir_size + + if not dryrun: + print "Deleting %s" % dir_to_upload + shutil.rmtree(dir_to_upload) + + if dryrun: + cur_freespace += dir_size + else: + cur_freespace = float(freespace(path)) + print "%.02f MBs now free" % (cur_freespace / 1024 / 1024) + print + + except Exception: + print "An unexpected error occured!" + error = True + traceback.print_exc() + + print "---------------------------------------" + if error: + pass + else: + pass + print "Finished successfully" if not error else "!!! Terminated abnormally !!!" + print "Current free space: %.02f MBs" % (cur_freespace / 1024 / 1024) + print "Reclaimed space: %.02f MBs" % (reclaimed_space / 1024 / 1024) + print "Directories uploaded: %s" % dirs_uploaded + print "Files uploaded: %s" % files_uploaded + + +if __name__ == '__main__': + if not 4 <= len(sys.argv) <= 5: + print "usage: dailyimgupload.py workingdir path megabytes [dryrun]" + sys.exit(1) + + wd = sys.argv[1] + if not os.path.isdir(wd): + print "Invalid working directory: %s" % wd + sys.exit(1) + print "Switching working directory to %s" % wd + os.chdir(wd) + + path = sys.argv[2] + if not os.path.isdir(path): + print "invalid image directory: %s" % path + sys.exit(1) + + mbs = sys.argv[3] + try: + target_free_mbs = float(mbs) + except ValueError: + print "invalid number of megabytes: %s" % mbs + sys.exit(1) + + if len(sys.argv) == 5: + dryrun = sys.argv[4] + if dryrun in ('true', 'false'): + dryrun = dryrun == 'true' + else: + print "invalid dry run argument: %s (must be either 'true' or 'false')" % dryrun + sys.exit(1) + else: + dryrun = True + + upload_dirs_until_free(path, target_free_mbs, dryrun) -- cgit v1.2.3-70-g09d2 From 13541b84837c8f360e2ae825d81ae489691b9e14 Mon Sep 17 00:00:00 2001 From: Scott Ostler Date: Fri, 3 Dec 2010 18:00:40 -0500 Subject: Add clojure 1.2.0 jars --- lib/clojure-1.2.0.jar | Bin 0 -> 3237168 bytes lib/clojure-contrib-1.2.0.jar | Bin 0 -> 477050 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 lib/clojure-1.2.0.jar create mode 100644 lib/clojure-contrib-1.2.0.jar diff --git a/lib/clojure-1.2.0.jar b/lib/clojure-1.2.0.jar new file mode 100644 index 0000000..82b549d Binary files /dev/null and b/lib/clojure-1.2.0.jar differ diff --git a/lib/clojure-contrib-1.2.0.jar b/lib/clojure-contrib-1.2.0.jar new file mode 100644 index 0000000..9765dd7 Binary files /dev/null and b/lib/clojure-contrib-1.2.0.jar differ -- cgit v1.2.3-70-g09d2 From e973500ec25b37d60fcfb0da25b341187fe7a359 Mon Sep 17 00:00:00 2001 From: Scott Ostler Date: Sun, 2 Jan 2011 15:59:49 -0500 Subject: Updated repl.bat w/ jedis jars --- bin/repl.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/repl.bat b/bin/repl.bat index 92c650c..09b9edd 100755 --- a/bin/repl.bat +++ b/bin/repl.bat @@ -1,3 +1,3 @@ REM Windows REPL script SHIFT -java -Xmx320m -server -cp lib/commons-io-1.4.jar;lib/commons-fileupload-1.2.1.jar;lib/commons-codec-1.3.jar;lib/clojure.jar;lib/clojure-contrib.jar;lib/compojure-3.2v3.jar;lib/jetty-6.1.24.jar;lib/jetty-util-6.1.24.jar;lib/servlet-api-2.5-6.1.14.jar;lib/jline-0.9.94.jar;lib/postgresql-8.4-701.jdbc4.jar;lib/stringtemplate-3.2.1.jar;lib/antlr-2.7.7.jar;lib/mail-1.4.4.jar;lib/jdom-1.1.jar;lib/rome-1.0.jar;lib/htmlcleaner-2.1.jar;lib/redis-clojure-1.0.4.jar;src/ jline.ConsoleRunner clojure.main -i %0 -r %* \ No newline at end of file +java -Xmx320m -server -cp lib/commons-io-1.4.jar;lib/commons-fileupload-1.2.1.jar;lib/commons-codec-1.3.jar;lib/commons-pool-1.5.5.jar;lib/clojure.jar;lib/clojure-contrib.jar;lib/compojure-3.2v3.jar;lib/jetty-6.1.24.jar;lib/jetty-util-6.1.24.jar;lib/servlet-api-2.5-6.1.14.jar;lib/jline-0.9.94.jar;lib/postgresql-8.4-701.jdbc4.jar;lib/stringtemplate-3.2.1.jar;lib/antlr-2.7.7.jar;lib/mail-1.4.4.jar;lib/jdom-1.1.jar;lib/rome-1.0.jar;lib/htmlcleaner-2.1.jar;lib/redis-clojure-1.0.4.jar;lib/jedis-1.4.0.jar;src/ jline.ConsoleRunner clojure.main -i %0 -r %* \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 1b06b06e7e0351dea457b1e96faecd2c705d91c2 Mon Sep 17 00:00:00 2001 From: Scott Ostler Date: Sun, 2 Jan 2011 17:03:04 -0500 Subject: Sort redis results by score, quickfix until redis broken connections can be fixed --- src/datalayer.clj | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/datalayer.clj b/src/datalayer.clj index 6b2a466..711dc65 100644 --- a/src/datalayer.clj +++ b/src/datalayer.clj @@ -106,7 +106,9 @@ order by count desc limit ? offset ?") (redis/zrevrange rkey 0 (dec num-popular-dumps))) msg-ids (map maybe-parse-int msg-ids)] (if-not (empty? msg-ids) - (tags/fetch-dumps-by-ids msg-ids viewer-nick)))) + (sort-by + #(* -1 (:count %)) + (tags/fetch-dumps-by-ids msg-ids viewer-nick))))) ;;;; Redis Favscores @@ -147,7 +149,9 @@ order by count desc limit ? offset ?") (redis/with-server redis-server (redis/zrevrange "hall" 0 (dec num-hall-dumps))))] (if-not (empty? ids) - (tags/fetch-dumps-by-ids ids viewer-nick)))) + (sort-by + #(* -1 (:count %)) + (tags/fetch-dumps-by-ids ids viewer-nick))))) ;;;; Message insertion -- cgit v1.2.3-70-g09d2 From 3cce3773433345af96549529c305186a95c1a271 Mon Sep 17 00:00:00 2001 From: dumpfmprod Date: Mon, 3 Jan 2011 23:38:22 -0500 Subject: sostler prod commic --- static/css/dump.css | 78 +++++++++++++++++++++++++++++++++++++++++--- static/js/invalid_domains.js | 3 +- template/banner.st | 2 +- template/fame.st | 2 +- template/profile.st | 35 ++++++++++++++++---- 5 files changed, 105 insertions(+), 15 deletions(-) diff --git a/static/css/dump.css b/static/css/dump.css index 55e3130..27bf99a 100755 --- a/static/css/dump.css +++ b/static/css/dump.css @@ -1733,11 +1733,11 @@ font-size:12px; position:absolute; top:0px; background-color:red; -padding:5px; -right:0px; - border-bottom-left-radius:5px; - -webkit-border-bottom-left-radius:5px; - -moz-border-radius-bottomleft:5px; +padding:3px; +left:0px; + border-bottom-right-radius:5px; + -webkit-border-bottom-right-radius:5px; + -moz-border-radius-bottomright:5px; } #dashadminmute a{color:white;} #edit-toggle{ @@ -1799,7 +1799,9 @@ margin-left:230px; font-family: 'HelveticaNeue-Light','Helvetica Neue Light','Helvetica Neue',Arial,Helvetica,sans-serif; font-size:50px; letter-spacing:-2px; +display:inline-black; margin-bottom:10px; +height:45px;word-wrap:suppress; } #middash h3{ @@ -1845,6 +1847,9 @@ width:550px; max-height:100px; height: expression(this.width > 50 ? 50: true); max-width:150px; + box-shadow: -1px 1px 10px #000; + -webkit-box-shadow:-1px 1px 10px #000; + -moz-box-shadow: -1px 1px 10px #000; } @@ -2161,3 +2166,66 @@ color:#000; text-shadow: 0px 1px 0px #fff; margin-left:20px;color:#66AACC; font-size:11px; } +/*MESSAGE STUFF*/ + + +a.msgbtn { + + padding:5px; +top:-7px; +right:-1px; +font-weight:500; + position: absolute; + font-size: 12.5px; + background: #fff; + color: #000; +border: 1px dotted #0C8FFF; + text-align: center; +font-family: Monaco, "Courier New", Courier, monospace; + cursor: pointer; + margin-left: 50px; + margin-top:6px; + + -webkit-user-select: none; + -moz-user-select: none; + text-decoration: none; + border-bottom-left-radius:5px; + -webkit-border-bottom-left-radius:5px; + -moz-border-radius-bottomleft:5px; + +} +a.msgbtn:active { + background:#eee; + +} +#directmsgs { + position: fixed; + right: -262px; + width: 245px; +padding:7px; + background-image:url("/static/img/thumbs/stripes.gif"); +border: 1px dotted #0C8FFF; +top:50px; +background-color:#fff; + height: 90%; + overflow-x: hidden; + +} +#directmsgs img{ + max-width:220px; + width: expression(this.width > 650 ? 650: true); + max-height:400px; + height: expression(this.width > 400 ? 400: true); +margin:5px; + box-shadow: -1px 1px 10px #000; + -webkit-box-shadow:-1px 1px 10px #000; + -moz-box-shadow: -1px 1px 10px #000; + +} +#directmsgs h2{ +padding-bottom:10px; + font-family: Monaco, "Courier New", Courier, monospace; + font-weight: 100; +font-size:15px; +} +#singlemsg{padding:5px;} \ No newline at end of file diff --git a/static/js/invalid_domains.js b/static/js/invalid_domains.js index ea1c1c5..a9ce909 100644 --- a/static/js/invalid_domains.js +++ b/static/js/invalid_domains.js @@ -87,5 +87,6 @@ var InvalidDomains = [ "http://carsdriveingallery.com", "http://xxxspacegirls.us", "http://www.newlog.com.ar", - "villagephotos.com" + "villagephotos.com", + "hereticpress.com" ]; diff --git a/template/banner.st b/template/banner.st index 6108c9a..691cd48 100644 --- a/template/banner.st +++ b/template/banner.st @@ -87,7 +87,7 @@
$if(user_nick)$ - checkout dump.fm in full-screen $else$ $endif$ + checkout dump.fm in full-screen - MYSTERY ROOM!!!!!!!! $else$ $endif$ $if(isadmin)$ - NAUGHTY BOYS DELIGHT $endif$
diff --git a/template/fame.st b/template/fame.st index 4735cab..b389d54 100644 --- a/template/fame.st +++ b/template/fame.st @@ -15,7 +15,7 @@
-

Hall Of Fame


updated hourly

+

Hall Of Fame

diff --git a/template/profile.st b/template/profile.st index 3aae2c2..6b54c43 100644 --- a/template/profile.st +++ b/template/profile.st @@ -10,6 +10,26 @@ + + + + $if(avatar)$ @@ -91,22 +111,23 @@
- $if(isadmin)$ -
+ + +messages!

Messages

+ $dms: { dm | -
- $dm.nick$ - +
+ $dm.nick$: $dm.content$ -
+
}$
- $endif$ +
-- cgit v1.2.3-70-g09d2 From 2890fd426aafbfe63d94bb1e327eaef1ddefceb1 Mon Sep 17 00:00:00 2001 From: Scott Ostler Date: Mon, 3 Jan 2011 23:50:37 -0500 Subject: refactored redis/datalayer code --- src/datalayer.clj | 36 +++++++++++++++++++++------ src/redisload.clj | 14 ++++++----- src/site.clj | 73 +++---------------------------------------------------- 3 files changed, 41 insertions(+), 82 deletions(-) diff --git a/src/datalayer.clj b/src/datalayer.clj index 711dc65..24c162a 100644 --- a/src/datalayer.clj +++ b/src/datalayer.clj @@ -10,8 +10,6 @@ user utils)) - - ;;;; Message lookup (defn recent-posts-query [user-id] @@ -81,6 +79,9 @@ WHERE u.nick = ANY(?)" ;;;; Popular Posts +(defn redis-popular-key [nick] + (str "popular:" nick)) + (def popular-dumps-qry " select u.nick, u.avatar, r.key, m.message_id, m.content, m.created_on, count(*) as count, array_agg(u2.nick) as user_nicks @@ -101,9 +102,10 @@ order by count desc limit ? offset ?") :favorited (some #(= % viewer-nick) favers))))) (defn fetch-popular-dumps-redis [nick viewer-nick] - (let [rkey (str "popular:" nick) - msg-ids (redis/with-server redis-server - (redis/zrevrange rkey 0 (dec num-popular-dumps))) + (let [msg-ids (redis/with-server redis-server + (redis/zrevrange (redis-popular-key nick) + 0 + (dec num-popular-dumps))) msg-ids (map maybe-parse-int msg-ids)] (if-not (empty? msg-ids) (sort-by @@ -113,11 +115,29 @@ order by count desc limit ? offset ?") ;;;; Redis Favscores +(def score-piece-map + (zipmap + [:pawn :knight :bishop :rook :queen :king :skull] + ["♟" "♞" "♝" "♜" "♛" "♚" "☠"])) + +(defn score-to-piece [score] + (cond (= score -1) :skull + (= score 0) :pawn + (< score 50) :knight + (< score 150) :bishop + (< score 300) :rook + (< score 1000) :queen + :else :king)) + +(def score-to-entity (comp score-piece-map score-to-piece)) + +(def redis-favscores-key "favscores") + (defn fetch-redis-directory [page num] (vec (for [t (with-jedis #(.zrevrangeWithScores % - "favscores" + redis-favscores-key (* page num) (dec (* (inc page) num))))] {:nick (.getElement t) @@ -144,10 +164,12 @@ order by count desc limit ? offset ?") ;;;; Redis Hall of Fame +(def redis-hall-key "hall") + (defn fetch-redis-hall [viewer-nick] (let [ids (map maybe-parse-int (redis/with-server redis-server - (redis/zrevrange "hall" 0 (dec num-hall-dumps))))] + (redis/zrevrange redis-hall-key 0 (dec num-hall-dumps))))] (if-not (empty? ids) (sort-by #(* -1 (:count %)) diff --git a/src/redisload.clj b/src/redisload.clj index 31a25f0..8796d9e 100644 --- a/src/redisload.clj +++ b/src/redisload.clj @@ -9,6 +9,8 @@ (defn redis-days [n] (* 24 60 60)) +;;;; Tag counters + (def tag-query " SELECT u.nick as author, @@ -65,7 +67,7 @@ WHERE (defn transmit-popular [] (doseq [[nick msgs] @popular-map] (let [sorted-msgs (sort #(>= (second %1) (second %2)) msgs) - userkey (str "popular:" nick)] + userkey (redis-popular-key nick)] (redis/atomically (redis/del key) (doseq [[msg-id score] (take (* num-popular-dumps 2) @@ -75,19 +77,19 @@ WHERE (defn transmit-favscores [] (redis/atomically - (redis/del "favscores") + (redis/del redis-favscores-key) (doseq [[nick score] @score-map] - (redis/zadd "favscores" score (lower-case nick)))) + (redis/zadd redis-favscores-key score (lower-case nick)))) (println "cached favscores for " (count @score-map) "users")) (defn transmit-hall [] (let [scores (take (* 2 num-hall-dumps) (sort #(>= (second %1) (second %2)) @hall-map))] (redis/atomically - (redis/del "hall") + (redis/del redis-hall-key) (doseq [[msg-id score] scores] - (redis/zadd "hall" score msg-id))))) - + (redis/zadd redis-hall-key score msg-id))) + (println "cached hall-of-fame"))) (println "streaming tags") (stream-tags [update-popular]) diff --git a/src/site.clj b/src/site.clj index 3ec07a5..663a6df 100644 --- a/src/site.clj +++ b/src/site.clj @@ -306,65 +306,6 @@ WHERE user_id IN [(session-assoc-from-db db-user) (resp-success "OK")]))))) -;; Fav scores - -(def *score-query* " -SELECT u.user_id, - u.nick, - COUNT(*) AS cnt -FROM tags t, - messages m, - users u -WHERE t.message_id = m.message_id - AND m.user_id != t.user_id - AND m.user_id = u.user_id -GROUP BY u.user_id, u.nick -ORDER BY cnt DESC -") - -(defn build-score-list [] - (let [res (vec (do-select [*score-query*]))] - {:list res - :map (zipmap (map :nick res) (map :cnt res))})) - -;; sostler: stop score refresh until redis cache can be added -(def *scores-refresh-period-sec* (* 29 60 9999999)) - -(def *user-scores* - (scheduled-agent build-score-list - *scores-refresh-period-sec* - [])) - -(def *piece-map* - (zipmap - [:pawn :knight :bishop :rook :queen :king :skull] - ["♟" "♞" "♝" "♜" "♛" "♚" "☠"])) - -(defn score-to-piece [score] - (cond (= score -1) :skull - (= score 0) :pawn - (< score 50) :knight - (< score 150) :bishop - (< score 300) :rook - (< score 1000) :queen - :else :king)) - -(def score-to-entity (comp *piece-map* score-to-piece)) - -(defn lookup-score [nick] - (if (= (lower-case nick) "scottbot") - -1 - (let [scores (:map (poll *user-scores*))] - (get scores nick 0)))) - -(defn get-user-ranking [offset num] - (if-let [ranking (:list (poll *user-scores*))] - (let [cnt (count ranking)] - (subvec ranking - (min cnt (* offset num)) - (min cnt (* (inc offset) num)))))) - - ;; Profile (defn pull-random-dump-images [dumps num] @@ -375,8 +316,6 @@ ORDER BY cnt DESC (comp take-images :content) dumps)))))) -(def use-redis-favscore true) - (defn profile ([session profile-nick] (profile session profile-nick "profile")) ([session profile-nick template] @@ -386,9 +325,7 @@ ORDER BY cnt DESC nick (:nick session) logger (make-time-logger) is-home (and nick (= nick profile-nick)) - score (if use-redis-favscore - (fetch-redis-favscore profile-nick) - (lookup-score profile-nick)) + score (fetch-redis-favscore profile-nick) dumps (logger tags/fetch-dumps :user-tag-id (:user_id session) :nick profile-nick @@ -457,9 +394,7 @@ ORDER BY cnt DESC (defn build-mini-profile [user-info] (let [st (fetch-template-fragment "mini_profile") nick (user-info :nick) - score (if use-redis-favscore - (fetch-redis-favscore nick) - (lookup-score nick))] + score (fetch-redis-favscore nick)] (doseq [a [:nick :avatar :contact :bio]] (let [v (user-info a)] (.setAttribute st (name a) @@ -1441,7 +1376,7 @@ ORDER BY cnt DESC (start-user-flusher!) (start-session-pruner!) -(if (not= *server-url* "http://dump.fm") - (start! random-poster)) +;(if (not= *server-url* "http://dump.fm") +; (start! random-poster)) -- cgit v1.2.3-70-g09d2 From 92b092823c21af1339e0d42716dc856357f93e85 Mon Sep 17 00:00:00 2001 From: Scott Ostler Date: Tue, 4 Jan 2011 15:42:23 -0500 Subject: Added topics, refactored recipient handling --- src/datalayer.clj | 90 +++++++++++++++++++++++++++++----------------- src/message.clj | 12 +++++-- src/site.clj | 75 ++++++++++++++++++++++++++------------ src/user.clj | 2 +- src/utils.clj | 20 +++++------ static/js/pichat.js | 58 ++++++++++++++++++++---------- template/log.st | 5 ++- template/popular.st | 6 ++-- template/profile.st | 18 ++++------ template/rooms/chat.st | 4 +-- template/single_message.st | 4 ++- template/tagged_dumps.st | 4 ++- template/topic.st | 39 ++++++++++++++++++++ template/userlog.st | 4 ++- 14 files changed, 233 insertions(+), 108 deletions(-) create mode 100644 template/topic.st diff --git a/src/datalayer.clj b/src/datalayer.clj index 24c162a..ecdc6dc 100644 --- a/src/datalayer.clj +++ b/src/datalayer.clj @@ -1,4 +1,5 @@ (ns datalayer + (:import java.util.Date) (:require redis tags) (:use clojure.contrib.sql @@ -82,25 +83,6 @@ WHERE u.nick = ANY(?)" (defn redis-popular-key [nick] (str "popular:" nick)) -(def popular-dumps-qry " -select u.nick, u.avatar, r.key, m.message_id, m.content, m.created_on, count(*) as count, - array_agg(u2.nick) as user_nicks -from users u, messages m, rooms r, tags t, users u2 -where lower(u.nick) = lower(?) -and u.user_id = m.user_id and m.message_id = t.message_id -and m.room_id = r.room_id and m.is_image = true and r.admin_only = false -and t.tag = 'favorite' -and t.user_id = u2.user_id -group by u.nick, u.avatar, r.key, m.message_id, m.content, m.created_on -order by count desc limit ? offset ?") - -(defn fetch-popular-dumps [nick viewer-nick] - (for [d (do-select [popular-dumps-qry nick 40 0])] - (let [favers (.getArray (:user_nicks d))] - (assoc d - :favers favers - :favorited (some #(= % viewer-nick) favers))))) - (defn fetch-popular-dumps-redis [nick viewer-nick] (let [msg-ids (redis/with-server redis-server (redis/zrevrange (redis-popular-key nick) @@ -177,10 +159,14 @@ order by count desc limit ? offset ?") ;;;; Message insertion +(defn direct-message-key [u-id] + (str "directmessage:" u-id)) + (def msg-insert-query "INSERT INTO messages (user_id, room_id, content, is_image, is_text) VALUES (?, ?, ?, ?, ?) RETURNING message_id, created_on") +;; Note: direct-message recipients are inserted into postgres, but topics aren't. (defn insert-message-into-postgres! [author-id room-id content is-image is-text recips] (with-connection *db* (transaction @@ -195,43 +181,81 @@ order by count desc limit ? offset ?") [msg-id author-id (:user_id r)])) [msg-id ts])))) -(defn insert-recips-into-redis! [recips author-id ts content] - (let [dm-json (json-str {"author_id" author-id - "recips" (map :nick recips) - "content" content})] +(defn insert-recips-into-redis! [recips author-id dt content] + (let [msg-json (json-str {"author_id" author-id + "recips" (map :nick recips) + "content" content}) + ts (.getTime dt)] (redis/with-server redis-server (redis/atomically (doseq [r recips] - (redis/zadd (str "directmessage:" (:user_id r)) - (.getTime ts) - dm-json)))))) + (redis/zadd (direct-message-key (:user_id r)) + ts + msg-json)))))) + +(defn topic-key [topic] + (str "topic:" topic)) + +(defn insert-topics-into-redis! [topics recips author-nick author-avatar dt msg-id content] + (let [ts (.getTime dt) + msg-json (json-str {"nick" author-nick + "avatar" author-avatar + "recips" (map :recips recips) + "content" content + "message_id" msg-id + "ts" ts})] + (redis/with-server redis-server + (redis/atomically + (doseq [t topics] + (redis/lpush (topic-key t) + msg-json)))))) -(defn insert-message! [author-id author-nick room-id content] +(defn insert-message! [author-id author-nick author-avatar room-id content] (let [msg-type (classify-msg content) is-image (boolean (#{:image :mixed} msg-type)) is-text (boolean (#{:mixed :text} msg-type)) recips (get-recips content) - [msg-id ts] (insert-message-into-postgres! author-id + topics (get-topics content) + [msg-id dt] (insert-message-into-postgres! author-id room-id content is-image is-text recips)] (if-not (empty? recips) - (insert-recips-into-redis! recips author-id ts content)) + (insert-recips-into-redis! recips author-id dt content)) + (if-not (empty? topics) + (insert-topics-into-redis! topics recips author-nick author-avatar dt msg-id content)) {:author author-nick :msg-id msg-id :room room-id - :db-ts ts + :db-ts dt :content content - :recips (map (comp lower-case :nick) recips)})) + :recips (map :nick recips) + :topics topics + })) -(defn fetch-private-messages [user-id] +(defn fetch-direct-messages [user-id] (for [dm (redis/with-server redis-server - (redis/zrevrange (str "directmessage:" user-id) 0 40))] + (redis/zrevrange (direct-message-key user-id) 0 40))] (let [dm (read-json dm) info (fetch-user-id (get dm "author_id"))] {"nick" (:nick info) "content" (get dm "content") "recips" (get dm "recips" []) "avatar" (:avatar info)}))) + +(def topic-fetch-num 40) + +(defn fetch-topic [viewer-id topic] + (let [redis-msgs (redis/with-server redis-server + (redis/lrange (topic-key topic) 0 topic-fetch-num)) + raw-msgs (for [m redis-msgs] + (let [m (keywordify (read-json m))] + (assoc m + :created_on (Date. (:ts m)))))] + (if viewer-id + (tags/add-user-favs-to-msgs + raw-msgs + viewer-id) + raw-msgs))) diff --git a/src/message.clj b/src/message.clj index a8e0e9b..9f1380b 100644 --- a/src/message.clj +++ b/src/message.clj @@ -1,5 +1,6 @@ (ns message - (:use user)) + (:use user + utils)) ;; Message parsing @@ -26,7 +27,7 @@ (defn get-recips [content] (filter boolean - (for [at-nick (re-seq recip-regex content)] + (for [at-nick (set (re-seq recip-regex content))] (fetch-nick (.substring (.trim at-nick) 1))))) (defn get-recips-from-msgs [msgs] @@ -37,3 +38,10 @@ boolean (for [r recips] (fetch-nick (.substring (.trim r) 1)))))) + +(def topic-regex #"(?:^|\s)#\w+") + +(defn get-topics [content] + (set + (for [r (re-seq topic-regex content)] + (lower-case (.substring r 1))))) diff --git a/src/site.clj b/src/site.clj index 663a6df..6ebfb73 100644 --- a/src/site.clj +++ b/src/site.clj @@ -316,6 +316,9 @@ WHERE user_id IN (comp take-images :content) dumps)))))) +(defn pull-recips [dumps] + (set (apply concat (map #(get % "recips") dumps)))) + (defn profile ([session profile-nick] (profile session profile-nick "profile")) ([session profile-nick template] @@ -330,8 +333,8 @@ WHERE user_id IN :user-tag-id (:user_id session) :nick profile-nick :limit 10) - dms (fetch-private-messages (:user_id user-info)) - recips (set (apply concat (map #(get % "recips") dms))) + dms (fetch-direct-messages (:user_id user-info)) + recips (pull-recips dms) imgs (pull-random-dump-images dumps 5)] (do (.setAttribute st "is_home" is-home) @@ -343,7 +346,7 @@ WHERE user_id IN (.setAttribute st "score_ent" (score-to-entity score)) (when-not (empty? dms) (.setAttribute st "dms" dms) - (.setAttribute st "recips" (json-str (map lower-case recips)))) + (.setAttribute st "recips" (json-str recips))) (if (not (empty? imgs)) (.setAttribute st "imgs" imgs)) (.setAttribute st "debug_log_items" (logger)) @@ -421,6 +424,7 @@ WHERE user_id IN :msg-id msg-id :date (if msg-id nil date) :limit (inc *dumps-per-page*)) + recips (map :nick (get-recips-from-msgs raw-dumps)) back-dumps (if (or date msg-id) (tags/fetch-dumps :nick (:nick user-info) @@ -432,8 +436,9 @@ WHERE user_id IN (.setAttribute st "nick" (:nick user-info)) (.setAttribute st "is_home" (= (:nick user-info) (:nick session))) (.setAttribute st "mini_profile" (build-mini-profile user-info)) - (if (> (count dumps) 0) + (when (> (count dumps) 0) (.setAttribute st "dumps" dumps)) + (.setAttribute st "recips" (json-str recips)) (.setAttribute st "prev" (if back-dumps (cond @@ -453,20 +458,18 @@ WHERE user_id IN ;; Who faved me -(def use-popular-redis true) - (defn popular [session profile-nick] (if-let [user-info (fetch-nick profile-nick)] (let [st (fetch-template "popular" session) profile-nick (:nick user-info) - raw-dumps (if use-popular-redis - (fetch-popular-dumps-redis profile-nick (:nick session)) - (fetch-popular-dumps profile-nick (:nick session))) + raw-dumps (fetch-popular-dumps-redis profile-nick (:nick session)) raw-dumps (filter #(> (:count %) 0) raw-dumps) + recips (get-recips-from-msgs raw-dumps) dumps (map process-message-for-output raw-dumps)] (.setAttribute st "nick" profile-nick) (.setAttribute st "mini_profile" (build-mini-profile user-info)) (.setAttribute st "dumps" dumps) + (.setAttribute st "recips" (json-str recips)) (.toString st)) (resp-error "NO_USER"))) @@ -538,6 +541,7 @@ WHERE user_id IN (if (= nick-from-url (:nick message)) (let [st (fetch-template "single_message" session)] (.setAttribute st "dump" (process-message-for-output message)) + (.setAttribute st "recips" (json-str (map :nick (get-recips (:content message))))) (.toString st)) (resp-error "NO_MESSAGE")) (resp-error "NO_MESSAGE"))) @@ -573,7 +577,7 @@ WHERE user_id IN (doto st (.setAttribute "users" (prepare-user-list room true)) (.setAttribute "messages" message-list) - (.setAttribute "recips" (json-str (map lower-case recips))) + (.setAttribute "recips" (json-str recips)) (.setAttribute "roomkey" (room :key)) (.setAttribute "isadminroom" (room :admin_only)) (.setAttribute "json_room_key" (json-str (room :key))) @@ -605,7 +609,7 @@ WHERE user_id IN :avatar (session :avatar)})) (commute users assoc nick (user-struct-from-session session)))) (resp-success (assoc (updates nick room old-ts) - :timestamp now))))) + :timestamp now))))) (defn validated-refresh [session params] (let [room-key (params :room) @@ -638,16 +642,16 @@ WHERE user_id IN mute (resp-error (format-mute mute)) :else (let [content (validated-content content session) - msg-info (insert-message! user-id nick (:room_id room) content) + msg-info (insert-message! user-id nick (:avatar session) (:room_id room) content) msg-id (:msg-id msg-info)] (dosync - (if (not (contains? (ensure (room :users)) nick)) - (login-user (user-struct-from-session session) room)) - (add-message (build-msg nick content msg-id (:recips msg-info)) room)) + (let [msg-struct (build-msg nick content msg-id (:recips msg-info))] + (if (not (contains? (ensure (room :users)) nick)) + (login-user (user-struct-from-session session) room)) + (add-message msg-struct room))) (resp-success {:msgid msg-id :recips (:recips msg-info)}))))) - (defn validated-msg [session params request] (cond (not (validate-room-access (params :room) session)) (resp-error "UNKNOWN_ROOM") @@ -655,7 +659,6 @@ WHERE user_id IN ;; Browser -;; TODO: make work for all rooms (defn browser [session] (let [room (lookup-room *default-room*) now (System/currentTimeMillis) @@ -675,6 +678,21 @@ WHERE user_id IN (.toString st))) +;; Topics + +(defn topic [session topic] + (let [topic (lower-case topic) + msgs (map + process-message-for-output + (fetch-topic (:user_id session) topic)) + recips (pull-recips msgs) + st (fetch-template "topic" session)] + (.setAttribute st "recips" (json-str recips)) + (.setAttribute st "topic" topic) + (if-not (empty? msgs) + (.setAttribute st "dumps" msgs)) + (.toString st))) + ;; Chat Log (defn log [session room offset params] @@ -690,7 +708,9 @@ WHERE user_id IN :image-only image-only :amount (+ 1 *dumps-per-page*) :offset dump-offset) - dumps (map tags/add-favorited-flag (take *dumps-per-page* raw-dumps) (repeat session)) + dumps (map tags/add-favorited-flag + (take *dumps-per-page* raw-dumps) + (repeat session)) ;; json-tags (for [dump dumps :when (not (empty? (dump :tags)))] ;; (json-str {"id" (dump :message_id) "tags" (dump :tags) })) dumps (map tags/remove-tags-for-output dumps) @@ -734,8 +754,6 @@ WHERE user_id IN (.setAttribute st "dumps" dumps) (.toString st))) - - ;; Altars ;; if :nick is in params, will fetch only altars by that nick @@ -887,6 +905,7 @@ WHERE user_id IN :hide-vip (not (:is_admin session)) :date (if msg-id nil date) :limit (inc *dumps-per-page*)) + recips (map :nick (get-recips-from-msgs raw-dumps)) back-dumps (if (or date msg-id) (tags/fetch-tagged-dumps :nick (:nick user-info) @@ -906,6 +925,7 @@ WHERE user_id IN (if (> (count raw-dumps) *dumps-per-page*) (.setAttribute st "next" (favorites-next-page-link (:nick user-info) (last raw-dumps)))) (.setAttribute st "dumps" dumps) + (.setAttribute st "recips" (json-str recips)) (.setAttribute st "infobar" (build-mini-profile user-info)) (.setAttribute st "page_title" (format "%s'S FAVS" (:nick user-info))) (.setAttribute st "debug_log_items" (logger)) @@ -1069,11 +1089,17 @@ WHERE user_id IN date (today) dest (open-file [*image-directory* date] filename) url (image-url-from-file "images" date dest) - msg-info (insert-message! (:user_id session) (:nick session) - (:room_id room) url)] + msg-info (insert-message! (:user_id session) + (:nick session) + (:avatar session) + (:room_id room) + url)] (copy (:tempfile image) dest) (dosync - (let [msg (build-msg (:nick session) url (:msg-id msg-info) (:recips msg-info))] + (let [msg (build-msg (:nick session) + url + (:msg-id msg-info) + (:recips msg-info))] (add-message msg room))) [200 "OK"]))) @@ -1180,6 +1206,9 @@ WHERE user_id IN (GET "/r/:room/log/:offset" (validated-log session (params :room) (params :offset) params)) (GET "/favicon.ico" (serve-static "static" "favicon.ico")) + + (GET "/t/:topic" (topic session (params :topic))) + (GET "/u/:nick" (redirect-to (str "/" (params :nick)))) (GET "/u/:nick/" (redirect-to (str "/" (params :nick)))) (GET "/u/:nick/tag/:tag" (tagged-dumps-by-nick session params (request-url request))) diff --git a/src/user.clj b/src/user.clj index 7641bd8..8380bce 100644 --- a/src/user.clj +++ b/src/user.clj @@ -18,7 +18,7 @@ ;;; User info cache -(def user-cache-size 500) +(def user-cache-size 99999) (def user-nick-cache (ref {})) (def user-id-cache (ref {})) diff --git a/src/utils.clj b/src/utils.clj index 8aaffba..ca527ac 100755 --- a/src/utils.clj +++ b/src/utils.clj @@ -27,7 +27,6 @@ db-name "dumpfm" db-user "postgres" db-pass "root"] - ; TODO: use c3p0 for pooling? (def *db* {:datasource (doto (new PGPoolingDataSource) (.setServerName db-host) (.setDatabaseName db-name) @@ -48,9 +47,8 @@ (throw (Exception. (str "Invalid url " u)))))) (defn get-ip [request] - (let [ip (get (:headers request) "x-real-ip") ; behind nginx - ip (if ip ip (:remote-addr request))] (str ip)) ; deployed locally -) + (let [ip (get (:headers request) "x-real-ip") ; behind nginx + ip (if ip ip (:remote-addr request))] (str ip))) ; deployed locally (defn append [& seqs] (reduce into (map vector seqs))) @@ -70,6 +68,9 @@ (defn stringify-and-escape [m] (zipmap (map str* (keys m)) (map escape-html-deep (vals m)))) +(defn keywordify [m] + (zipmap (map keyword (keys m)) (vals m))) + (defn nor [& args] (not-any? identity args)) @@ -371,16 +372,15 @@ (.setRefreshInterval template-group 10) (defn initialize-template [st session] + (.setAttribute st "domain" config/*server-url*) (if (session :nick) (doto st (.setAttribute "user_email" (session :email)) (.setAttribute "user_nick" (session :nick)) (.setAttribute "user_avatar" (if (non-empty-string? (session :avatar)) - (session :avatar) nil)) - (.setAttribute "isadmin" (session :is_admin)) - (.setAttribute "domain" config/*server-url*)) - (doto st - (.setAttribute "domain" config/*server-url*)))) + (session :avatar) + nil)) + (.setAttribute "isadmin" (session :is_admin))))) (defn fetch-template [template session] (try @@ -446,7 +446,7 @@ { :result result :time (System/currentTimeMillis)}) result))))) -;; Taken from Programming Clojure by Stuart Halloway +;; From Programming Clojure by Stuart Halloway (defn index-filter [pred coll] (for [[idx elt] (indexed coll) :when (pred elt)] idx)) diff --git a/static/js/pichat.js b/static/js/pichat.js index a33209b..72f7d0d 100644 --- a/static/js/pichat.js +++ b/static/js/pichat.js @@ -120,6 +120,7 @@ Log.initialize(); URLRegex = /((\b(http\:\/\/|https\:\/\/|ftp\:\/\/)|(www\.))+(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?)/gi; PicRegex = /\.(jpg|jpeg|png|gif|bmp|svg|fid)$/i; RecipRegex = /(^|\s)@\w+/g; +TopicRegex = /(^|\s)#\w+/g; function getImagesAsArray(text) { @@ -135,24 +136,45 @@ function getImagesAsArray(text) { return imgs } -function linkify(text, recips) { - LastMsgContainsImage = false; - var recipWrapper = function(text) { return recipientReplace(text, recips); }; - return text.replace(URLRegex, linkReplace).replace(RecipRegex, recipWrapper); +function topicReplace(text) { + text = $.trim(text).toLowerCase(); + var topicLabel = text.substring(1); + return ' ' + text + ' '; } function recipientReplace(atText, recips) { + recips = recips || []; + + var space = ''; if (atText[0] == ' ') { atText = atText.slice(1); - var space = ' '; - } else { - var space = ''; + space = ' '; } - var nick = atText.slice(1); - if (!recips || recips.indexOf(nick.toLowerCase()) == -1) { + + var nick = atText.slice(1).toLowerCase(); + var matchedRecip; + for (var i = 0; i < recips.length; i++) { + if (recips[i].toLowerCase() == nick) { + matchedRecip = recips[i]; + break; + } + } + + if (matchedRecip) { + return space + '@' + matchedRecip + ''; + } else { return space + atText; - } else - return space + '' + atText + ''; + } +} + +function linkify(text, recips) { + console.log(recips) + LastMsgContainsImage = false; + var recipWrapper = function(text) { return recipientReplace(text, recips); }; + return text + .replace(URLRegex, linkReplace) + .replace(RecipRegex, recipWrapper) + .replace(TopicRegex, topicReplace); } // use this in escapeHtml to turn everyone's text lIkE tHiS @@ -330,7 +352,7 @@ function setImgsEnable() { function buildMsgContent(content, recips) { if (content.substr(0,6) == "") - return content.substr(6,content.length - 13) + return content.substr(6,content.length - 13); else return linkify(escapeHtml(content), recips); } @@ -712,7 +734,7 @@ function enableProfileEdit() { activateProfileEditable(); } -function initProfile() { +function initProfile(recips) { Search.initInpage(); $(".linkify-text").each(function() { var text = jQuery(this).text(); @@ -720,7 +742,7 @@ function initProfile() { }); $(".linkify-full").each(function() { - $(this).html(buildMsgContent($(this).text(), Recips)); + $(this).html(buildMsgContent($(this).text(), recips)); }); $('#edit-toggle').click(enableProfileEdit); @@ -732,11 +754,11 @@ function initProfile() { }); }; -function initLog() { - Search.initInpage() +function initLog(recips) { + Search.initInpage(); $('.logged-dump .content').each(function() { var t = $(this); - t.html(buildMsgContent(t.text())); + t.html(buildMsgContent(t.text(), recips)); }); initLogThumb(".logged-dump .thumb", '.dump'); } @@ -797,7 +819,7 @@ function paletteToChat(img){ chatText += " " chatText += $(img).attr("src") + " " $("#msgInput").val(chatText) - $("#msgInput").focus().val($("#msgInput").val()) //http://stackoverflow.com/questions/1056359/ + $("#msgInput").focus().val($("#msgInput").val()) // http://stackoverflow.com/questions/1056359/ paletteHide() } diff --git a/template/log.st b/template/log.st index 92a0f75..ab4eb53 100644 --- a/template/log.st +++ b/template/log.st @@ -3,7 +3,10 @@ dump.fm log $head()$ diff --git a/template/popular.st b/template/popular.st index 65eeece..c900dd9 100644 --- a/template/popular.st +++ b/template/popular.st @@ -2,10 +2,10 @@ dump.fm - $nick$'s popular $head()$ - - diff --git a/template/profile.st b/template/profile.st index 6b54c43..82c77e6 100644 --- a/template/profile.st +++ b/template/profile.st @@ -2,16 +2,16 @@ $nick$'s dump.fm - - + + $head()$ - - - + $if(avatar)$ @@ -124,11 +123,6 @@ jQuery(document).ready(function() {
}$ - - -
$footer()$ diff --git a/template/rooms/chat.st b/template/rooms/chat.st index f7ca888..a8269a6 100644 --- a/template/rooms/chat.st +++ b/template/rooms/chat.st @@ -10,9 +10,9 @@ \ \:\/:/ \ \:\ /:/ \ \:\ \ \::/ \ \::/ \ \:\ \ \::/ \ \:\/:/ \ \:\ \ \:\ \ \:\ \ \:\ \__\/ \ \::/ \ \:\ \ \:\ \ \:\ \ \:\ - \__\/ \__\/ \__\/ \__\/ \__\/ + \__\/ \__\/ \__\/ \__\/ \__\/ \___\/ - (c)2010 dump.fm --> + (c)2011 dump.fm --> diff --git a/template/single_message.st b/template/single_message.st index 1428f2b..3bf49ac 100644 --- a/template/single_message.st +++ b/template/single_message.st @@ -3,7 +3,9 @@ dump.fm $head()$ diff --git a/template/tagged_dumps.st b/template/tagged_dumps.st index 44c4b5e..b488afb 100644 --- a/template/tagged_dumps.st +++ b/template/tagged_dumps.st @@ -4,7 +4,9 @@ $head()$ diff --git a/template/topic.st b/template/topic.st new file mode 100644 index 0000000..71451b2 --- /dev/null +++ b/template/topic.st @@ -0,0 +1,39 @@ + + + #$topic$ - dump.fm + $head()$ + + + + $banner()$ +
+
+
+

#$topic$

+

+
+
+ $if(dumps)$ + + $dumps: { d | $log_dump(dump=d)$ }$ + + $else$ + Topic #$topic$ doesn't exist yet! + $endif$ +
+
+
+ $footer()$ +
+
+
+ + + + + diff --git a/template/userlog.st b/template/userlog.st index c073ce3..4e67c82 100644 --- a/template/userlog.st +++ b/template/userlog.st @@ -3,7 +3,9 @@ $nick$'s dump.fm $head()$ -- cgit v1.2.3-70-g09d2 From 457125462cd658b6660289a292c367a0d560a792 Mon Sep 17 00:00:00 2001 From: Scott Ostler Date: Tue, 4 Jan 2011 16:17:46 -0500 Subject: Second revision of topics --- src/datalayer.clj | 24 +++++++++++++----------- src/site.clj | 14 +++++++------- static/js/pichat.js | 1 - template/topic.st | 51 ++++++++++++++++++++++++++++++--------------------- 4 files changed, 50 insertions(+), 40 deletions(-) diff --git a/src/datalayer.clj b/src/datalayer.clj index ecdc6dc..8590a7d 100644 --- a/src/datalayer.clj +++ b/src/datalayer.clj @@ -181,9 +181,10 @@ WHERE u.nick = ANY(?)" [msg-id author-id (:user_id r)])) [msg-id ts])))) -(defn insert-recips-into-redis! [recips author-id dt content] +(defn insert-recips-into-redis! [recips author-id dt content room-key] (let [msg-json (json-str {"author_id" author-id "recips" (map :nick recips) + "key" room-key "content" content}) ts (.getTime dt)] (redis/with-server redis-server @@ -196,12 +197,13 @@ WHERE u.nick = ANY(?)" (defn topic-key [topic] (str "topic:" topic)) -(defn insert-topics-into-redis! [topics recips author-nick author-avatar dt msg-id content] +(defn insert-topics-into-redis! [topics recips author-nick author-avatar dt msg-id content room-key] (let [ts (.getTime dt) msg-json (json-str {"nick" author-nick "avatar" author-avatar - "recips" (map :recips recips) + "recips" (map :nick recips) "content" content + "key" room-key "message_id" msg-id "ts" ts})] (redis/with-server redis-server @@ -210,29 +212,29 @@ WHERE u.nick = ANY(?)" (redis/lpush (topic-key t) msg-json)))))) -(defn insert-message! [author-id author-nick author-avatar room-id content] +(defn insert-message! [author-id author-nick author-avatar room content] (let [msg-type (classify-msg content) is-image (boolean (#{:image :mixed} msg-type)) is-text (boolean (#{:mixed :text} msg-type)) recips (get-recips content) topics (get-topics content) [msg-id dt] (insert-message-into-postgres! author-id - room-id + (:room_id room) content is-image is-text recips)] - (if-not (empty? recips) - (insert-recips-into-redis! recips author-id dt content)) - (if-not (empty? topics) - (insert-topics-into-redis! topics recips author-nick author-avatar dt msg-id content)) + (when-not (:admin_only room) + (if-not (empty? recips) + (insert-recips-into-redis! recips author-id dt content (:key room))) + (if-not (empty? topics) + (insert-topics-into-redis! topics recips author-nick author-avatar dt msg-id content (:key room)))) {:author author-nick :msg-id msg-id - :room room-id + :room (:room_id room) :db-ts dt :content content :recips (map :nick recips) - :topics topics })) (defn fetch-direct-messages [user-id] diff --git a/src/site.clj b/src/site.clj index 6ebfb73..df5d9f7 100644 --- a/src/site.clj +++ b/src/site.clj @@ -71,9 +71,9 @@ (assoc d :created_on (.getTime (d :created_on)))) (defn message-room-link [m] - (if (= (:key m) "dumpfm") - "http://dump.fm/chat" - (format "http://%s.dump.fm" (:key m)))) + (if (default-room? (:key m *default-room*)) + "http://dump.fm/" + (format "http://%s.dump.fm/" (:key m)))) (defn process-message-for-output [d] (escape-html-deep @@ -317,7 +317,7 @@ WHERE user_id IN dumps)))))) (defn pull-recips [dumps] - (set (apply concat (map #(get % "recips") dumps)))) + (set (apply concat (map #(get % "recips" []) dumps)))) (defn profile ([session profile-nick] (profile session profile-nick "profile")) @@ -642,7 +642,7 @@ WHERE user_id IN mute (resp-error (format-mute mute)) :else (let [content (validated-content content session) - msg-info (insert-message! user-id nick (:avatar session) (:room_id room) content) + msg-info (insert-message! user-id nick (:avatar session) room content) msg-id (:msg-id msg-info)] (dosync (let [msg-struct (build-msg nick content msg-id (:recips msg-info))] @@ -686,7 +686,7 @@ WHERE user_id IN process-message-for-output (fetch-topic (:user_id session) topic)) recips (pull-recips msgs) - st (fetch-template "topic" session)] + st (fetch-template "topic" session)] (.setAttribute st "recips" (json-str recips)) (.setAttribute st "topic" topic) (if-not (empty? msgs) @@ -1092,7 +1092,7 @@ WHERE user_id IN msg-info (insert-message! (:user_id session) (:nick session) (:avatar session) - (:room_id room) + room url)] (copy (:tempfile image) dest) (dosync diff --git a/static/js/pichat.js b/static/js/pichat.js index 72f7d0d..cc51613 100644 --- a/static/js/pichat.js +++ b/static/js/pichat.js @@ -168,7 +168,6 @@ function recipientReplace(atText, recips) { } function linkify(text, recips) { - console.log(recips) LastMsgContainsImage = false; var recipWrapper = function(text) { return recipientReplace(text, recips); }; return text diff --git a/template/topic.st b/template/topic.st index 71451b2..1594364 100644 --- a/template/topic.st +++ b/template/topic.st @@ -3,37 +3,46 @@ #$topic$ - dump.fm $head()$ - + $banner()$ -
-
-
-

#$topic$

-

-
-
+
+
+
+

#$topic$

+

+
+
$if(dumps)$ - $dumps: { d | $log_dump(dump=d)$ }$ + $dumps: { d | $topic_dump(dump=d)$ }$ $else$ Topic #$topic$ doesn't exist yet! $endif$ -
-
-
- $footer()$ -
-
-
-
-
- + +
+
+ $if(prev)$ + + $else$ + + $endif$ + + $if(next)$ + + $else$ + + $endif$ +
+
+ $footer()$ +
+
+ -- cgit v1.2.3-70-g09d2 From 9186beaddef218162edcc73b7a8fec30a9a63fa7 Mon Sep 17 00:00:00 2001 From: Scott Ostler Date: Tue, 4 Jan 2011 16:22:40 -0500 Subject: fix init-template bug --- src/utils.clj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils.clj b/src/utils.clj index ca527ac..760ae63 100755 --- a/src/utils.clj +++ b/src/utils.clj @@ -380,7 +380,8 @@ (.setAttribute "user_avatar" (if (non-empty-string? (session :avatar)) (session :avatar) nil)) - (.setAttribute "isadmin" (session :is_admin))))) + (.setAttribute "isadmin" (session :is_admin)))) + st) (defn fetch-template [template session] (try -- cgit v1.2.3-70-g09d2 From 2bc29e5de23e4cb6d9c97196a8ba7981e621c686 Mon Sep 17 00:00:00 2001 From: Scott Ostler Date: Tue, 4 Jan 2011 16:24:58 -0500 Subject: Add topic_dump.st --- template/topic_dump.st | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 template/topic_dump.st diff --git a/template/topic_dump.st b/template/topic_dump.st new file mode 100644 index 0000000..cc52e4e --- /dev/null +++ b/template/topic_dump.st @@ -0,0 +1,8 @@ +
+
+ $dump.created_on$ -- by $dump.nick$ in $dump.key$ +
+
$dump.content$
+
+$share_buttons()$ +
-- cgit v1.2.3-70-g09d2 From f46044e56199750c9fbda3dec3edd1336ada98ad Mon Sep 17 00:00:00 2001 From: Scott Ostler Date: Tue, 4 Jan 2011 16:27:39 -0500 Subject: Fixed pichat.js urls --- static/js/pichat.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/static/js/pichat.js b/static/js/pichat.js index cc51613..7c7dd0a 100644 --- a/static/js/pichat.js +++ b/static/js/pichat.js @@ -139,7 +139,7 @@ function getImagesAsArray(text) { function topicReplace(text) { text = $.trim(text).toLowerCase(); var topicLabel = text.substring(1); - return ' ' + text + ' '; + return ' ' + text + ' '; } function recipientReplace(atText, recips) { @@ -161,7 +161,7 @@ function recipientReplace(atText, recips) { } if (matchedRecip) { - return space + '@' + matchedRecip + ''; + return space + '@' + matchedRecip + ''; } else { return space + atText; } @@ -384,7 +384,7 @@ function buildUserDiv(user) { + escapeHtml(user.nick) + ''; } else { return ''; } @@ -394,7 +394,7 @@ function buildUserDiv(user) { function buildFav(f) { var h = '
' - + '' + + '' + '' + f.from + '' + ' just faved you!' + '
'; -- cgit v1.2.3-70-g09d2 From 034acfa61c9f5667f11f43659c02eb9bae7e94f5 Mon Sep 17 00:00:00 2001 From: Scott Ostler Date: Tue, 4 Jan 2011 16:29:41 -0500 Subject: topic links open in new window --- static/js/pichat.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/js/pichat.js b/static/js/pichat.js index 7c7dd0a..884e01f 100644 --- a/static/js/pichat.js +++ b/static/js/pichat.js @@ -139,7 +139,7 @@ function getImagesAsArray(text) { function topicReplace(text) { text = $.trim(text).toLowerCase(); var topicLabel = text.substring(1); - return ' ' + text + ' '; + return ' ' + text + ' '; } function recipientReplace(atText, recips) { -- cgit v1.2.3-70-g09d2 From a5a3b7079531da5e8f0662fe223d18e3477599d9 Mon Sep 17 00:00:00 2001 From: Scott Ostler Date: Tue, 4 Jan 2011 16:39:37 -0500 Subject: Fix trim bug in topics --- src/message.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/message.clj b/src/message.clj index 9f1380b..5b3b66f 100644 --- a/src/message.clj +++ b/src/message.clj @@ -44,4 +44,4 @@ (defn get-topics [content] (set (for [r (re-seq topic-regex content)] - (lower-case (.substring r 1))))) + (lower-case (.substring (.trim r) 1))))) -- cgit v1.2.3-70-g09d2 From 53d4542aa5c4165bd7e1b4ca5218ff62aaa51b8f Mon Sep 17 00:00:00 2001 From: Scott Ostler Date: Tue, 4 Jan 2011 16:40:56 -0500 Subject: Fix popular links --- src/site.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/site.clj b/src/site.clj index df5d9f7..ba9336b 100644 --- a/src/site.clj +++ b/src/site.clj @@ -464,7 +464,7 @@ WHERE user_id IN profile-nick (:nick user-info) raw-dumps (fetch-popular-dumps-redis profile-nick (:nick session)) raw-dumps (filter #(> (:count %) 0) raw-dumps) - recips (get-recips-from-msgs raw-dumps) + recips [] ; (get-recips-from-msgs raw-dumps) dumps (map process-message-for-output raw-dumps)] (.setAttribute st "nick" profile-nick) (.setAttribute st "mini_profile" (build-mini-profile user-info)) -- cgit v1.2.3-70-g09d2 From 7d68c6986c0ba08dcb4c2f3dcca318584021099c Mon Sep 17 00:00:00 2001 From: Scott Ostler Date: Tue, 4 Jan 2011 16:44:24 -0500 Subject: Fixed popular recips glitch --- src/site.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/site.clj b/src/site.clj index ba9336b..5b20361 100644 --- a/src/site.clj +++ b/src/site.clj @@ -464,7 +464,7 @@ WHERE user_id IN profile-nick (:nick user-info) raw-dumps (fetch-popular-dumps-redis profile-nick (:nick session)) raw-dumps (filter #(> (:count %) 0) raw-dumps) - recips [] ; (get-recips-from-msgs raw-dumps) + recips (map :nick (get-recips-from-msgs raw-dumps)) dumps (map process-message-for-output raw-dumps)] (.setAttribute st "nick" profile-nick) (.setAttribute st "mini_profile" (build-mini-profile user-info)) -- cgit v1.2.3-70-g09d2