summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--db/0-create.psql1
-rw-r--r--src/rooms.clj4
-rw-r--r--src/site.clj242
-rwxr-xr-xsrc/utils.clj2
-rwxr-xr-xstatic/css/dump.css4
-rw-r--r--static/js/pichat.js29
-rw-r--r--static/test/bugchat.html14
-rw-r--r--static/test/bugchat.js138
-rw-r--r--template/directory.st8
-rw-r--r--template/profile.st14
10 files changed, 251 insertions, 205 deletions
diff --git a/db/0-create.psql b/db/0-create.psql
index aea6d63..112e774 100644
--- a/db/0-create.psql
+++ b/db/0-create.psql
@@ -37,6 +37,7 @@ CREATE INDEX messages_user_id_idx ON messages (user_id);
CREATE INDEX messages_room_id_idx ON messages (room_id);
CREATE INDEX messages_created_on_idx ON messages (created_on);
CREATE INDEX messages_is_image_idx ON messages (is_image);
+CREATE INDEX messages_user_created_on_idx ON messages (user_id, created_on desc);
-- Queries to support:
-- 1) What messages are tagged x? (ordered by time, popularity)
diff --git a/src/rooms.clj b/src/rooms.clj
index 32239d2..e18a434 100644
--- a/src/rooms.clj
+++ b/src/rooms.clj
@@ -107,10 +107,10 @@
(or (do-select ["SELECT user_id FROM users WHERE lower(nick) = ?"
(lower-case nick)])
(do
+ (println "Creating bot " nick)
(do-select ["INSERT INTO users (nick, hash, email)
VALUES (?, ?, ?) RETURNING user_id"
- nick "GARBAGE" "info@dump.fm"])
- (println "Creating bot " nick)))))
+ nick "GARBAGE" "info@dump.fm"])))))
(defn get-or-create-room-bot! [key]
(let [nick (str "~" key)]
diff --git a/src/site.clj b/src/site.clj
index 4454da3..eefbbc3 100644
--- a/src/site.clj
+++ b/src/site.clj
@@ -105,14 +105,9 @@
(map process-user (vals @(room :users))))
(defn updates [room since]
- (let [m {"users" (prepare-user-list room)
- "messages" (map process-message-for-json
- (new-messages room since))}
- topic @(room :topic)]
- (if topic
- (assoc m "topic" topic)
- m)))
-
+ {"users" (prepare-user-list room)
+ "messages" (map process-message-for-json
+ (new-messages room since))})
(defn count-messages-by-nick [nick image-only]
(let [query (str "SELECT COUNT(*)
@@ -146,7 +141,8 @@
;; User-id/nick cache
;; I keep needing to grab user-id from a nick so I thought I'd cache them
-
+;; @timb: I just duplicated this in the user-info map :(
+;; we should reconcile our user caches
(def user-id-cache (ref {}))
(def *user-id-cache-size* 500)
@@ -312,19 +308,46 @@ WHERE t.message_id = m.message_id
AND m.user_id != t.user_id
AND m.user_id = u.user_id
GROUP BY u.nick
-ORDER BY cnt DESC;
+ORDER BY cnt DESC
")
-(def *scores-refresh-period-sec* (* 30 60))
+(def *user-info-query* "
+SELECT u.nick,
+ u.user_id,
+ u.avatar,
+ LAST.content,
+ LAST.message_id
+FROM users u
+ LEFT JOIN messages LAST
+ ON u.user_id = LAST.user_id
+ AND LAST.created_on = (SELECT MAX(created_on)
+ FROM messages
+ WHERE user_id = u.user_id
+ AND room_id != 2
+ AND is_image)
+")
+
+
+(defn build-user-info-map []
+ (let [res (do-select [*user-info-query*])]
+ (zipmap (map :nick res) res)))
-(defn compute-scores []
- (let [res (do-select [*score-query*])]
- (zipmap (map :nick res)
- (map :cnt res))))
+(defn build-score-list []
+ (let [res (vec (do-select [*score-query*]))]
+ {:list res
+ :map (zipmap (map :nick res) (map :cnt res))}))
+
+(def *scores-refresh-period-sec* (* 30 60))
+(def *user-info-refresh-period-sec* 300)
(def *user-scores*
- (scheduled-agent (no-args-adaptor compute-scores)
+ (scheduled-agent (no-args-adaptor build-score-list)
*scores-refresh-period-sec*
+ []))
+
+(def *user-info*
+ (scheduled-agent (no-args-adaptor build-user-info-map)
+ *user-info-refresh-period-sec*
{}))
(def *piece-map*
@@ -343,39 +366,29 @@ ORDER BY cnt DESC;
(def score-to-entity (comp *piece-map* score-to-piece))
-;; Profile
+(defn lookup-score [nick]
+ (if (= (lower-case nick) "scottbot")
+ -1
+ (let [scores (:map (poll *user-scores*))]
+ (get scores nick 0))))
-(def *zoeee-query* "
-SELECT m.content, m.message_id, m.created_on,
- u.nick, u.avatar, r.key,
- array_to_string(ARRAY(SELECT nick || ' ' || tag
- FROM tags, users
- WHERE message_id = m.message_id AND tags.user_id = users.user_id), ' ') as tags
-FROM messages m, users u,rooms r
-WHERE u.nick = 'zoeee'
-AND m.user_id = u.user_id
-AND m.message_id <= 519399
-AND m.message_id >= 517713
-AND m.is_image = true
-AND m.room_id = r.room_id
-AND r.room_id = 1
-ORDER BY created_on DESC;
-")
+(defn lookup-user-info [nick]
+ (if-let [i (get (poll *user-info*) nick)]
+ (if-let [score (lookup-score nick)]
+ (assoc i :score (lookup-score nick)
+ :score_ent (score-to-entity score))
+ i)
+ {}))
-(defn zoeee-nudes [session]
- (let [raw-dumps (map tags/parse-tags-from-row-as-tag-map
- (do-select [*zoeee-query*]))
- dumps (map tags/add-favorited-flag raw-dumps (repeat session))
- dumps (map tags/remove-tags-for-output dumps)
- dumps (map process-message-for-output dumps)
- st (fetch-template "profile" session)
- user-info (fetch-nick "zoeee")]
- (doseq [a [:nick :avatar :contact :bio]]
- (let [v (user-info a)]
- (.setAttribute st (name a)
- (if (non-empty-string? v) (escape-html v)))))
- (.setAttribute st "dumps" dumps)
- (.toString st)))
+(defn get-user-ranking [offset num]
+ (let [ranking (:list (poll *user-scores*))
+ count (count ranking)]
+ (subvec ranking
+ (min count (* offset num))
+ (min count (* (inc offset) num)))))
+
+
+;; Profile
(defn profile
([session profile-nick offset] (profile session profile-nick offset "profile"))
@@ -388,9 +401,7 @@ ORDER BY created_on DESC;
is-home (and nick (= nick profile-nick))
has-avatar (non-empty-string? (user-info :avatar))
offset (maybe-parse-int offset 0)
- score (if (= (lower-case profile-nick) "scottbot")
- -1
- (or ((poll *user-scores*) profile-nick) 0))
+ score (lookup-score profile-nick)
dump-offset (* offset *dumps-per-page*)
raw-dumps (logger tags/fetch-dumps-by-nick
:nick profile-nick
@@ -441,51 +452,20 @@ ORDER BY created_on DESC;
;; Directory
(def *per-directory-page* 25)
-(def *directory-refresh-period-sec* (* 60 60))
-
-(def *directory-update-query* "
-SELECT m.user_id,
- u.nick,
- u.avatar,
- message_id,
- m.created_on,
- msg_count,
- content
-FROM (SELECT user_id,
- created_on,
- message_id,
- content,
- MAX(created_on) OVER (PARTITION BY user_id) max_created_on,
- COUNT(*) OVER (PARTITION BY user_id) msg_count
- FROM messages
- WHERE room_id = 1
- AND is_image = true) AS m,
- users u
-WHERE m.created_on = max_created_on
- AND m.user_id = u.user_id
-ORDER BY msg_count DESC")
-
-(defn fetch-directory []
- (vec (do-select [*directory-update-query*])))
-(def *directory-list*
- (scheduled-agent fetch-directory
- *directory-refresh-period-sec*
- []))
-
-(defn directory-search [offset]
- (let [directory (poll *directory-list*)
- users (subvec directory
- (min (count directory)
- (* offset *per-directory-page*))
- (min (count directory)
- (* (inc offset) *per-directory-page*)))]
- (when (> (count users) 0)
- (map process-directory-listing users))))
+(defn process-directory-entry [entry]
+ (let [info (lookup-user-info (:nick entry))]
+ (assoc (stringify-and-escape info)
+ "score_ent" (:score_ent info))))
+(defn get-directory-info [offset]
+ (map process-directory-entry
+ (get-user-ranking offset
+ *per-directory-page*)))
+
(defn directory [session offset]
- (let [st (fetch-template "directory" session)
- users (directory-search offset)]
+ (let [st (fetch-template "directory" session)
+ users (get-directory-info offset)]
(.setAttribute st "users" users)
(cond (= offset 0) (.setAttribute st "prev" false)
(= offset 1) (.setAttribute st "prev" "")
@@ -493,8 +473,6 @@ ORDER BY msg_count DESC")
(if (> offset 0)
(.setAttribute st "cur" offset))
(.setAttribute st "next" (str "/" (inc offset)))
- (if (zero? (count (poll *directory-list*)))
- (.setAttribute st "notloaded" true))
(.toString st)))
;; Single posts
@@ -513,59 +491,6 @@ ORDER BY msg_count DESC")
(resp-error "NO_USER")))
-;; Topics
-
-(defn valid-topic? [topic]
- topic)
-
-(defn valid-deadline? [deadline]
- deadline)
-
-(defn topic-map-from-room [r]
- (let [topic (or @(r :topic) {})]
- {"key" (r :key)
- "topic" (topic :topic)
- "deadline" (topic :deadline)
- "maker" (topic :maker)}))
-
-(defn validate-topic-list [session]
- (if-vip
- (let [st (fetch-template "topic_list" session)]
- (.setAttribute st "rooms"
- (map topic-map-from-room (vals @rooms)))
- (.toString st))))
-
-(defn set-topic! [room topic deadline maker]
- (dosync (ref-set (room :topic)
- {:topic topic
- :deadline deadline
- :maker maker})))
-
-(defn end-topic! [room]
- (dosync (ref-set (room :topic) nil)))
-
-(defn validate-set-topic [session params]
- (if-vip
- (let [room (lookup-room (params :room))
- topic (params :topic)
- deadline (params :deadline)
- maker (params :maker)]
- (cond (not (valid-topic? topic)) (resp-error "INVALID_TOPIC")
- (not (valid-deadline? deadline)) (resp-error "INVALID_DEADLINE")
- (not room) (resp-error "INVALID_ROOM")
- (not maker) (resp-error "NOT_MAKER")
- :else (do
- (set-topic! room topic deadline maker)
- (resp-success "OK"))))))
-
-(defn validate-end-topic [session params]
- (if-vip
- (if-let [room (lookup-room (params :room))]
- (do
- (end-topic! room)
- (resp-success "OK"))
- (resp-error "INVALID_ROOM"))))
-
;; Chat
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -619,16 +544,16 @@ ORDER BY msg_count DESC")
(defn refresh [session params room]
(dosync
- (let [now (System/currentTimeMillis)
- since (maybe-parse-long (params :since) now)
- nick (session :nick)
- users (room :users)]
+ (let [now (System/currentTimeMillis)
+ since (maybe-parse-long (params :since) now)
+ nick (session :nick)
+ users (room :users)]
(if nick
(if-let [user-info (@users nick)]
; Incorporate avatar updates
(commute users assoc nick (merge user-info {:last-seen now
:avatar (session :avatar)}))
- (commute (room :users) assoc nick (user-struct-from-session session))))
+ (commute users assoc nick (user-struct-from-session session))))
(resp-success (assoc (updates room since) :timestamp now :v *chat-version-number*)))))
(defn validated-refresh [session params]
@@ -981,12 +906,9 @@ ORDER BY msg_count DESC")
;; Compojure Routes
(defn serve-static [dir path]
- ; TODO: cache other static files (js, css, etc.)
- (let [cache-header (if (re-find pic-regex path)
- {:headers {"Cache-Control" "max-age=604800,public"}}
- {})]
- [cache-header
- (serve-file dir path)]))
+ (if (= path "")
+ (redirect-to "http://dump.fm")
+ (serve-file dir path)))
(defroutes static
(GET "/static/*" (serve-static "static" (params :*)))
@@ -1034,9 +956,6 @@ ORDER BY msg_count DESC")
(POST "/msg" (validated-msg session params))
(POST "/submit-registration" (register session params))
(POST "/update-profile" (update-profile session params))
- (GET "/topic-list" (validate-topic-list session))
- (POST "/set-topic" (validate-set-topic session params))
- (POST "/end-topic" (validate-end-topic session params))
(GET "/directory" (directory session 0))
(GET "/directory/:offset"
(directory session (maybe-parse-int (params :offset) 0)))
@@ -1064,7 +983,6 @@ ORDER BY msg_count DESC")
(GET "/error/ie" (serve-template "error_ie" session))
;; Put username routes below all others in priority
- (GET "/zoeee/nudes" (zoeee-nudes session))
(GET "/:nick" (profile session (params :nick) "0"))
(GET "/:nick/" (profile session (params :nick) "0"))
(GET "/:nick/:offset" (profile session (params :nick) (params :offset)))
diff --git a/src/utils.clj b/src/utils.clj
index d278e56..52f8399 100755
--- a/src/utils.clj
+++ b/src/utils.clj
@@ -186,7 +186,7 @@
(defn do-count [query]
((first (with-connection *db*
(with-query-results rs query
- (doall rs))))
+ (vec rs))))
:count))
(defn do-delete [table query]
diff --git a/static/css/dump.css b/static/css/dump.css
index 1aa7668..7097a55 100755
--- a/static/css/dump.css
+++ b/static/css/dump.css
@@ -417,7 +417,7 @@ opacity:0.87;
z-index:18;
text-align: left;
}
-#userList a:hover{color:#000;}
+#userList a:hover{color:#ffffff;}
.username{height:30px;
margin-top:6px;
line-height:20px;
@@ -439,7 +439,7 @@ width:100%;
height:100%;
background-image:url(/static/img/moverc.png);
background-repeat:repeat-x;
-color:#000;
+color:#fff;
text-decoration:none;
background-color:#f3f3f3;
border-top-right-radius:5px;
diff --git a/static/js/pichat.js b/static/js/pichat.js
index 84a9b79..e2ab061 100644
--- a/static/js/pichat.js
+++ b/static/js/pichat.js
@@ -352,26 +352,6 @@ function isDuplicateMessage(m) {
}
}
-var CurrentTopic = null;
-
-function isSameTopic(curTopic, newTopic) {
- if (!!curTopic != !!newTopic) { return false; }
- else if (!curTopic) { return false; } // => !newTopic also
- else {
- return curTopic.topic == newTopic.topic &&
- curTopic.deadline == newTopic.deadline &&
- curTopic.maker == newTopic.maker;
- }
-}
-
-function updateTopic(newTopic) {
- if (isSameTopic(CurrentTopic, newTopic)) { return; }
- alert('new topic');
- CurrentTopic = newTopic;
- $('#topic').text(topic.topic);
-
-}
-
function refresh() {
var onSuccess = function(json) {
try {
@@ -390,9 +370,6 @@ function refresh() {
if (typeof UnseenMsgCounter !== 'undefined' && !HasFocus) {
UnseenMsgCounter += messages.length;
}
- if (json.topic) {
- updateTopic(json.topic);
- }
} catch(e) {
if (IsAdmin && window.console) {
console.error(e);
@@ -976,7 +953,7 @@ function parseDomain(host){
// Away notification
var UnseenMsgCounter = 0;
-var OrigTitle = $('title').text();
+var OrigTitle = "";
var HasFocus = true;
function onFocus() {
@@ -1004,3 +981,7 @@ function startTitleUpdater() {
$(window).focus(onFocus);
setTimeout(titleUpdater, 2000);
}
+
+$(function() {
+ OrigTitle = $('title').text();
+}); \ No newline at end of file
diff --git a/static/test/bugchat.html b/static/test/bugchat.html
new file mode 100644
index 0000000..548eb6d
--- /dev/null
+++ b/static/test/bugchat.html
@@ -0,0 +1,14 @@
+<html>
+ <head>
+ <title>BUG CHAT</title>
+ <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
+ <script type="text/javascript" src="/static/test/bugchat.js"></script>
+ <script>
+ $(initClient);
+ </script>
+ </head>
+ <body>
+ <div id="msgs">
+ </div>
+ </body>
+</html>
diff --git a/static/test/bugchat.js b/static/test/bugchat.js
new file mode 100644
index 0000000..5d9a7b5
--- /dev/null
+++ b/static/test/bugchat.js
@@ -0,0 +1,138 @@
+var alphaChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+function generateRandomKey(length) {
+ s = "";
+ for (var i = 0; i < length; i++) {
+ var r = Math.floor(Math.random() * 26);
+ s += alphaChars[r];
+ }
+ return s;
+}
+
+function formatTime() {
+ var a_p = "";
+ var d = new Date();
+ var curr_hour = d.getHours();
+ if (curr_hour < 12)
+ {
+ a_p = "AM";
+ }
+ else
+ {
+ a_p = "PM";
+ }
+ if (curr_hour == 0)
+ {
+ curr_hour = 12;
+ }
+ if (curr_hour > 12)
+ {
+ curr_hour = curr_hour - 12;
+ }
+
+ if (curr_hour.length == 1)
+ curr_hour = "0" + curr_hour;
+
+ var curr_min = d.getMinutes();
+
+ curr_min = curr_min + "";
+
+ if (curr_min.length == 1)
+ {
+ curr_min = "0" + curr_min;
+ }
+ return curr_hour + ":" + curr_min + " " + a_p;
+}
+
+Key = generateRandomKey(10);
+Timestamp = 0;
+Counter = 0;
+ClientMap = {};
+
+function showError(err) {
+ var msg = formatTime() + " " + err;
+ console.error(msg);
+ $('#msgs').append($('<div>').css('color', 'red').text(msg));
+};
+
+
+function handleMessages(msgs) {
+ $.map(msgs, function(m) {
+ var split = m.content.split("-");
+ if (split.length != 2) {
+ showError("Bad message " + m.content);
+ return;
+ }
+ var client = split[0];
+ var i = parseInt(split[1]);
+ console.warn(client + " " + i);
+
+ if (client in ClientMap) {
+ var p = ClientMap[client];
+ if (i - p != 1) {
+ showError("[" + Key + "] Error for client " + client
+ + "! Expected " + (p+1) + ", got " + i);
+ }
+ }
+ ClientMap[client] = i;
+ });
+}
+
+function refresh() {
+ var onSuccess = function(json) {
+ try {
+ Timestamp = json.timestamp;
+ handleMessages(json.messages);
+ } catch(e) {
+ console.error(e);
+ $('#msgs').append($('<div>').css('color', 'red').text(e));
+ }
+ setTimeout(refresh, 1000);
+ };
+ var onError = function(resp, textStatus, errorThrown) {
+ console.error($.trim(resp.responseText));
+ setTimeout(refresh, 1000);
+ };
+
+ $.ajax({
+ type: 'GET',
+ timeout: 5000,
+ url: '/refresh',
+ data: { 'room': 'test', 'since': Timestamp },
+ cache: false,
+ dataType: 'json',
+ success: onSuccess,
+ error: onError
+ });
+}
+
+function postMessageWrapper() {
+ var delay = Math.ceil(1000 + Math.random() * 3000);
+ setTimeout(postMessage, delay);
+}
+
+function postMessage() {
+ var content = Key + "-" + Counter;
+ Counter++;
+ var onError = function(resp, textStatus, errorThrown) {
+ showError("Error posting " + content + ": " + resp.responseText);
+ postMessageWrapper();
+ };
+
+ $.ajax({
+ type: 'POST',
+ timeout: 5000,
+ url: '/msg',
+ data: { 'room': 'test', 'content': content },
+ cache: false,
+ dataType: 'json',
+ success: postMessageWrapper,
+ error: onError
+ });
+}
+
+function initClient() {
+ showError("Initializing client " + Key);
+ refresh();
+ postMessageWrapper();
+}; \ No newline at end of file
diff --git a/template/directory.st b/template/directory.st
index d49dfea..d9129ff 100644
--- a/template/directory.st
+++ b/template/directory.st
@@ -19,7 +19,7 @@
<div id="log">
<br>
<div id="dprofile">
- <h2> DUMP STARS </h2><br><h3>Ordered by post count</h3>
+ <h2> DUMP STARS </h2><br><h3>Ordered by fav count</h3>
</div>
@@ -30,6 +30,12 @@
$users:{ dump |
<div class="dlogged-dump" id="message-$dump.message_id$">
<a href="/$dump.nick$">
+ $if(dump.score_ent)$
+ <h8>
+ fav score: $dump.score$
+ <h9>$dump.score_ent$</h9>
+ </h8>
+ $endif$
<div id="usernicks"> <b>$dump.nick$</b></div>
$if(dump.avatar)$
<div id="dlogavatar">
diff --git a/template/profile.st b/template/profile.st
index 0634b05..e530e4a 100644
--- a/template/profile.st
+++ b/template/profile.st
@@ -78,19 +78,7 @@
<div id="date">
<div type="text" id="datepicker"></div></div>
</div>
- <div id="adsenseprofile" style="display:none;">
- <script type="text/javascript"><!--
-google_ad_client = "pub-9863902168532765";
-/* 200x200, created 5/23/10 */
-google_ad_slot = "0464631788";
-google_ad_width = 200;
-google_ad_height = 200;
-//-->
-</script>
-<script type="text/javascript"
-src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
-</script>
-</div>
+
$else$
<div class="logged-dump dump $if(dump.favorited)$favorite$endif$" id="message-$dump.message_id$" nick="$dump.nick$">