summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Ostler <sbsotler@gmail.com>2011-01-08 17:03:30 -0500
committerScott Ostler <sbsotler@gmail.com>2011-01-08 17:03:30 -0500
commit1e308142eba46bfa25614c14fd4a8899452bf0ce (patch)
treec666f00f93b5e0a6167de8a60b55e57b4536f0f4
parentbbac5e0ea48d2e443da6c9901ff09c11e8010f83 (diff)
parent7d68c6986c0ba08dcb4c2f3dcca318584021099c (diff)
Merge branch 'master' of ssh://dump.fm/pichat/repo
-rwxr-xr-xbin/repl.bat2
-rw-r--r--lib/clojure-1.2.0.jarbin0 -> 3237168 bytes
-rw-r--r--lib/clojure-contrib-1.2.0.jarbin0 -> 477050 bytes
-rw-r--r--[-rwxr-xr-x]scripts/dailyimgupload.py318
-rw-r--r--src/datalayer.clj140
-rw-r--r--src/message.clj12
-rw-r--r--src/redisload.clj14
-rw-r--r--src/site.clj152
-rw-r--r--src/user.clj2
-rwxr-xr-xsrc/utils.clj21
-rwxr-xr-xstatic/css/dump.css78
-rw-r--r--static/js/invalid_domains.js3
-rw-r--r--static/js/pichat.js61
-rw-r--r--template/banner.st2
-rw-r--r--template/fame.st2
-rw-r--r--template/log.st5
-rw-r--r--template/popular.st6
-rw-r--r--template/profile.st43
-rw-r--r--template/rooms/chat.st4
-rw-r--r--template/single_message.st4
-rw-r--r--template/tagged_dumps.st4
-rw-r--r--template/topic.st48
-rw-r--r--template/topic_dump.st8
-rw-r--r--template/userlog.st4
24 files changed, 564 insertions, 369 deletions
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
diff --git a/lib/clojure-1.2.0.jar b/lib/clojure-1.2.0.jar
new file mode 100644
index 0000000..82b549d
--- /dev/null
+++ b/lib/clojure-1.2.0.jar
Binary files 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
--- /dev/null
+++ b/lib/clojure-contrib-1.2.0.jar
Binary files differ
diff --git a/scripts/dailyimgupload.py b/scripts/dailyimgupload.py
index 502d1d0..e7378b1 100755..100644
--- a/scripts/dailyimgupload.py
+++ b/scripts/dailyimgupload.py
@@ -1,160 +1,158 @@
-#!/usr/bin/env python
-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)
- print "throwing error to test email"
- sys.exit(1) # test email system
+#!/usr/bin/env python
+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)
diff --git a/src/datalayer.clj b/src/datalayer.clj
index 6b2a466..8590a7d 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
@@ -10,8 +11,6 @@
user
utils))
-
-
;;;; Message lookup
(defn recent-posts-query [user-id]
@@ -81,41 +80,46 @@ WHERE u.nick = ANY(?)"
;;;; Popular Posts
-(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 redis-popular-key [nick]
+ (str "popular:" nick))
(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)
- (tags/fetch-dumps-by-ids msg-ids viewer-nick))))
+ (sort-by
+ #(* -1 (:count %))
+ (tags/fetch-dumps-by-ids msg-ids viewer-nick)))))
;;;; Redis Favscores
+(def score-piece-map
+ (zipmap
+ [:pawn :knight :bishop :rook :queen :king :skull]
+ ["&#9823;" "&#9822;" "&#9821;" "&#9820;" "&#9819;" "&#9818;" "&#9760;"]))
+
+(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)
@@ -142,19 +146,27 @@ 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)
- (tags/fetch-dumps-by-ids ids viewer-nick))))
+ (sort-by
+ #(* -1 (:count %))
+ (tags/fetch-dumps-by-ids ids viewer-nick)))))
;;;; 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
@@ -169,43 +181,83 @@ 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 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
(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-message! [author-id author-nick room-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 :nick recips)
+ "content" content
+ "key" room-key
+ "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 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)
- [msg-id ts] (insert-message-into-postgres! author-id
- room-id
+ topics (get-topics content)
+ [msg-id dt] (insert-message-into-postgres! author-id
+ (:room_id room)
content
is-image
is-text
recips)]
- (if-not (empty? recips)
- (insert-recips-into-redis! recips author-id ts 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
- :db-ts ts
+ :room (:room_id room)
+ :db-ts dt
:content content
- :recips (map (comp lower-case :nick) recips)}))
+ :recips (map :nick recips)
+ }))
-(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..5b3b66f 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 (.trim r) 1)))))
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..5b20361 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
@@ -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]
- ["&#9823;" "&#9822;" "&#9821;" "&#9820;" "&#9819;" "&#9818;" "&#9760;"]))
-
-(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,7 +316,8 @@ ORDER BY cnt DESC
(comp take-images :content)
dumps))))))
-(def use-redis-favscore true)
+(defn pull-recips [dumps]
+ (set (apply concat (map #(get % "recips" []) dumps))))
(defn profile
([session profile-nick] (profile session profile-nick "profile"))
@@ -386,15 +328,13 @@ 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
: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)
@@ -406,7 +346,7 @@ ORDER BY cnt DESC
(.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))
@@ -457,9 +397,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)
@@ -486,6 +424,7 @@ ORDER BY cnt DESC
: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)
@@ -497,8 +436,9 @@ ORDER BY cnt DESC
(.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
@@ -518,20 +458,18 @@ ORDER BY cnt DESC
;; 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 (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))
(.setAttribute st "dumps" dumps)
+ (.setAttribute st "recips" (json-str recips))
(.toString st))
(resp-error "NO_USER")))
@@ -603,6 +541,7 @@ ORDER BY cnt DESC
(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")))
@@ -638,7 +577,7 @@ ORDER BY cnt DESC
(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)))
@@ -670,7 +609,7 @@ ORDER BY cnt DESC
: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)
@@ -703,16 +642,16 @@ ORDER BY cnt DESC
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 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")
@@ -720,7 +659,6 @@ ORDER BY cnt DESC
;; Browser
-;; TODO: make work for all rooms
(defn browser [session]
(let [room (lookup-room *default-room*)
now (System/currentTimeMillis)
@@ -740,6 +678,21 @@ ORDER BY cnt DESC
(.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]
@@ -755,7 +708,9 @@ ORDER BY cnt DESC
: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)
@@ -799,8 +754,6 @@ ORDER BY cnt DESC
(.setAttribute st "dumps" dumps)
(.toString st)))
-
-
;; Altars
;; if :nick is in params, will fetch only altars by that nick
@@ -952,6 +905,7 @@ ORDER BY cnt DESC
: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)
@@ -971,6 +925,7 @@ ORDER BY cnt DESC
(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))
@@ -1134,11 +1089,17 @@ ORDER BY cnt DESC
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
+ 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"])))
@@ -1245,6 +1206,9 @@ ORDER BY cnt DESC
(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)))
@@ -1441,7 +1405,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))
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..760ae63 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,16 @@
(.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))))
+ st)
(defn fetch-template [template session]
(try
@@ -446,7 +447,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/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/static/js/pichat.js b/static/js/pichat.js
index a33209b..884e01f 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,44 @@ 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 ' <a target="_blank" href="http://dump.fm/t/' + topicLabel + '">' + text + '</a> ';
}
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 + '<a target="_blank" href="http://dump.fm/' + matchedRecip + '">@' + matchedRecip + '</a>';
+ } else {
return space + atText;
- } else
- return space + '<a target="_blank" href="/' + nick + '">' + atText + '</a>';
+ }
+}
+
+function linkify(text, 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 +351,7 @@ function setImgsEnable() {
function buildMsgContent(content, recips) {
if (content.substr(0,6) == "<safe>")
- return content.substr(6,content.length - 13)
+ return content.substr(6,content.length - 13);
else return linkify(escapeHtml(content), recips);
}
@@ -363,7 +384,7 @@ function buildUserDiv(user) {
+ escapeHtml(user.nick) + '</a></div>';
} else {
return '<div class="username">'
- + '<a href="/' + escapeHtml(user.nick) + '" target="_blank">'
+ + '<a href="http://dump.fm/' + escapeHtml(user.nick) + '" target="_blank">'
+ '<img src="/static/img/noinfo.png" width="50" height="50">'
+ escapeHtml(user.nick) + '</a></div>';
}
@@ -373,7 +394,7 @@ function buildUserDiv(user) {
function buildFav(f) {
var h = '<div class="fav-note">'
- + '<img src="/static/img/thumbs/chatheartover.gif">'
+ + '<img src="http://dump.fm/static/img/thumbs/chatheartover.gif">'
+ '<a href="http://dump.fm/' + f.from + '">' + f.from + '</a>'
+ '&nbsp;<span>just faved you!</span>'
+ '</div>';
@@ -712,7 +733,7 @@ function enableProfileEdit() {
activateProfileEditable();
}
-function initProfile() {
+function initProfile(recips) {
Search.initInpage();
$(".linkify-text").each(function() {
var text = jQuery(this).text();
@@ -720,7 +741,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 +753,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 +818,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/banner.st b/template/banner.st
index 6108c9a..691cd48 100644
--- a/template/banner.st
+++ b/template/banner.st
@@ -87,7 +87,7 @@
<div id="dumplist">
$if(user_nick)$
- <a href="http://dump.fm/fullscreen">checkout dump.fm in full-screen </a> $else$ <style>#dumplist{z-index:-1!important;}</style> $endif$
+ <a href="http://dump.fm/fullscreen">checkout dump.fm in full-screen </a> - <a href="http://abcdef4.dump.fm/">MYSTERY ROOM!!!!!!!! </a> $else$ <style>#dumplist{z-index:-1!important;}</style> $endif$
$if(isadmin)$ - <a href="http://vip.dump.fm/">NAUGHTY BOYS DELIGHT </a>
$endif$
</div>
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 @@
<div id="userListp">
<img src="http://dump.fm/static/img/halloffametrophy.gif" id="halltrophy">
- <h2>Hall Of Fame </h2><br><h3>updated hourly</h3>
+ <h2>Hall Of Fame </h2>
</div>
<div id="messageList">
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 @@
<title>dump.fm log</title>
$head()$
<script>
- jQuery(document).ready(initLog);
+ var Recips = [];
+ jQuery(function() {
+ initLog(Recips)
+ });
</script>
</head>
<body>
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 @@
<head>
<title>dump.fm - $nick$'s popular</title>
$head()$
-
-
<script>
- jQuery(document).ready(initLog);
+ jQuery(function() {
+ initLog([])
+ });
</script>
</head>
diff --git a/template/profile.st b/template/profile.st
index 3aae2c2..82c77e6 100644
--- a/template/profile.st
+++ b/template/profile.st
@@ -2,14 +2,33 @@
<head>
<title>$nick$'s dump.fm</title>
<meta property="og:image" content="$avatar$"/>
- <meta property="og:title" content="$nick$'s dump.fm"/>
- <meta property="og:site_name" content="dump.fm"/>
+ <meta property="og:title" content="$nick$'s dump.fm"/>
+ <meta property="og:site_name" content="dump.fm"/>
$head()$
<script src="/static/js/jquery.editinplace.1.0.1.packed.js" type="text/javascript"></script>
<script src="/static/js/ajaxupload.js"></script>
<script>
- jQuery(document).ready(initProfile);
+ jQuery(function() {
+ initProfile($recips$);
+ });
</script>
+ <script>
+//MESSAGE STUFF
+
+jQuery(document).ready(function() {
+ jQuery('#msgbtn').toggle(
+
+ function(){
+
+ jQuery("#directmsgs").animate({right: "0px"}, 400);
+ },
+ function()
+ {
+ jQuery("#directmsgs").animate({right: "-263px"}, 400);
+
+ });
+ });
+ </script>
</head>
<body class="profiledash">
$if(avatar)$
@@ -91,23 +110,19 @@
</div>
</div>
- $if(isadmin)$
- <br />
+
+
+<a href="#"class="msgbtn" id="msgbtn">messages!</a>
<div id="directmsgs">
<h2>Messages</h2>
+
$dms: { dm |
- <div class="directmsg">
- <b><a href="/$dm.nick$">$dm.nick$</a></b>
- <img src="$dm.avatar$" height="20" width="20" />
+ <div id="singlemsg">
+ <b><a href="/$dm.nick$">$dm.nick$</a>:</b>
<span class="linkify-full">$dm.content$</span>
- </div>
+ </div>
}$
</div>
- <script>
- var Recips = $recips$;
- </script>
- $endif$
-
</div>
<div id="footerc">
$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 -->
<html>
<head>
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 @@
<title>dump.fm</title>
$head()$
<script>
- jQuery(document).ready(initLog);
+ jQuery(function() {
+ initLog($recips$);
+ });
</script>
</head>
<body class="permalink">
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()$
<link rel="stylesheet" media="screen" type="text/css" href="http://dump.fm/static/css/dump.css">
<script>
- jQuery(document).ready(initLog);
+ jQuery(function() {
+ initLog($recips$);
+ });
</script>
</head>
<body>
diff --git a/template/topic.st b/template/topic.st
new file mode 100644
index 0000000..1594364
--- /dev/null
+++ b/template/topic.st
@@ -0,0 +1,48 @@
+<html>
+ <head>
+ <title>#$topic$ - dump.fm</title>
+ $head()$
+ <script>
+ jQuery(function() {
+ initLog($recips$);
+ });
+ </script>
+ </head>
+ <body>
+ $banner()$
+ <div id="content">
+ <div id="messagePanep">
+ <div id="userListp">
+ <h2><a href="/t/$topic$">#$topic$</a></h2>
+ <br><h3></h3>
+ </div>
+ <div id="messageList">
+ $if(dumps)$
+ <span class="content">
+ $dumps: { d | $topic_dump(dump=d)$ }$
+ </span>
+ $else$
+ <span>Topic #$topic$ doesn't exist yet!</span>
+ $endif$
+ </div>
+ <div id="msgInputDiv">
+ <div id="msginputrapper">
+ $if(prev)$
+ <a href="/$nick$/whofaved/$prev$"><input id="prevbutton" value="<- Prev" readonly="true"></a>
+ $else$
+ <input id="prevbutton" readonly="true">
+ $endif$
+
+ $if(next)$
+ <a href="/$nick$/whofaved/$next$"> <input id="nextbutton" value="Next ->" readonly="true"></a>
+ $else$
+ <input id="nextbutton" value="nomodumps" readonly="true">
+ $endif$
+ </div>
+ <div id="footerc">
+ $footer()$
+ </div>
+ </div>
+ </div>
+ </body>
+</html>
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 @@
+<div class="logged-dump dump $if(dump.favorited)$favorite$endif$" id="message-$dump.message_id$" nick="$dump.nick$">
+ <div>
+ $dump.created_on$ -- by <a href="/$dump.nick$"><b>$dump.nick$</b></a> in <b><a href="$dump.roomlink$">$dump.key$</a></b>
+ </div>
+ <div class="content">$dump.content$</div>
+<hr/>
+$share_buttons()$
+</div>
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 @@
<title>$nick$'s dump.fm</title>
$head()$
<script>
- jQuery(document).ready(initLog);
+ jQuery(function() {
+ initLog($recips$);
+ });
</script>
</head>
<body>