From 4b2986ed19c4a57516fbbba71e525383a1f8b437 Mon Sep 17 00:00:00 2001 From: sostler Date: Fri, 28 May 2010 04:00:37 -0400 Subject: Added fav notification --- src/feed.clj | 8 ++--- src/site.clj | 86 +++++++++++++++++++++++++++++++++-------------------- src/tags.clj | 30 ++++++++++++++----- src/user.clj | 6 ++++ static/css/dump.css | 42 ++++++++++++++++++++++++++ static/js/pichat.js | 36 ++++++++++++++++++++-- template/chat.st | 25 ++++++++-------- 7 files changed, 175 insertions(+), 58 deletions(-) diff --git a/src/feed.clj b/src/feed.clj index 3a3cc35..ada83fc 100755 --- a/src/feed.clj +++ b/src/feed.clj @@ -108,10 +108,10 @@ WHERE NOT EXISTS (SELECT 1 (def *feed-refresh-period-sec* (* 20 60)) -(def *feed-downloader* - (scheduled-agent process-all-feeds! - *feed-refresh-period-sec* - nil)) +;(def *feed-downloader* +; (scheduled-agent process-all-feeds! +; *feed-refresh-period-sec* +; nil)) ;; Testing diff --git a/src/site.clj b/src/site.clj index 45ee9e5..6c6a9dd 100644 --- a/src/site.clj +++ b/src/site.clj @@ -24,12 +24,6 @@ scheduled-agent user)) -(defstruct user-struct :nick :user_id :avatar :last-seen) - -(defn user-struct-from-session [session] - (struct user-struct (session :nick) (session :user_id) (session :avatar) - (System/currentTimeMillis))) - ;; Configuration (def *server-url* @@ -87,10 +81,13 @@ (assoc d :created_on (format-timestamp (d :created_on))) d)))) -(defn new-messages [room since-ts] - (let [since-date (new Date (long since-ts))] - (reverse (take-while (fn [m] (.after (m :created_on) since-date)) - @(room :messages))))) +(defn new-messages [room ts] + (reverse (take-while #(.after (% :created_on) ts) + @(room :messages)))) + +(defn new-favs [nick ts] + (filter #(.after (:added %) ts) + (get @fav-map nick []))) (defn process-user [u] (stringify-and-escape (strip-empty-vals u))) @@ -103,10 +100,11 @@ ; Sorting is done on client (map process-user (vals @(room :users)))) -(defn updates [room since] +(defn updates [nick room ts] {"users" (prepare-user-list room) "messages" (map process-message-for-json - (new-messages room since))}) + (new-messages room ts)) + "favs" (new-favs nick ts)}) (defn count-messages-by-nick [nick image-only] (let [query (str "SELECT COUNT(*) @@ -128,16 +126,20 @@ LIMIT ? OFFSET ?")] (do-select [query nick *dumps-per-page* offset])))) - -(defn fetch-public-message-by-id [m-id] - (let [query "SELECT m.content, m.created_on, m.user_id, u.nick, u.avatar +(defn fetch-message-by-id [m-id] + (let [query "SELECT m.message_id, m.content, m.created_on, m.user_id, + u.nick, u.avatar, r.key, r.admin_only FROM messages m, users u, rooms r WHERE m.user_id = u.user_id AND r.room_id = m.room_id - AND r.admin_only = false AND m.message_id = ?"] (first (do-select [query (maybe-parse-int m-id -1)])))) +(defn fetch-public-message-by-id [m-id] + (let [msg (fetch-message-by-id m-id)] + (if (and msg (not (:admin_only msg))) + msg))) + ;; 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 :( @@ -544,16 +546,18 @@ FROM users u (defn refresh [session params room] (dosync (let [now (System/currentTimeMillis) - since (maybe-parse-long (params :since) now) + old-ts (new Date (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)})) + :avatar (session :avatar)})) (commute users assoc nick (user-struct-from-session session)))) - (resp-success (assoc (updates room since) :timestamp now :v *chat-version-number*))))) + (resp-success (assoc (updates nick room old-ts) + :timestamp now + :v *chat-version-number*))))) (defn validated-refresh [session params] (let [room-key (params :room) @@ -675,21 +679,39 @@ FROM users u (let [path-without-domain (nth (re-find #"//[^/]+/(.+)" url) 1)] (nth (re-split #"/|\?" path-without-domain) position))) -(defn add-tag [user-id message-id tag] +(defn add-tag [user msg tag] (try - (do-insert "tags" ["user_id" "message_id" "tag"] [user-id (maybe-parse-int message-id) (normalize-tag-for-db tag)]) - true + (do-insert "tags" + ["user_id" "message_id" "tag"] + [(:user_id user) (msg :message_id) tag]) + (if (and (= tag "favorite") + (not (= (msg :nick) (user :nick)))) + (insert-fav-notification! (msg :nick) + (user :nick) + (user :avatar) + (msg :content))) + true ; catch error when inserting duplicate tags - (catch Exception e false))) + (catch Exception e false))) -; to do: don't let people set tags on messages they can't access (defn validated-add-tag [session params] (if (session :nick) - (if (add-tag (session :user_id) (params :message_id) (params :tag)) - (resp-success "OK") - (resp-error "TAG_EXISTS_ALREADY_OR_SOMETHING_ELSE_IS_FUCKED")) - (resp-error "NO_USER"))) + (let [nick (session :nick) + user-id (session :user_id) + user-admin? (session :admin-only) + msg-id (params :message_id) + tag (validate-tag (params :tag)) + msg (fetch-message-by-id msg-id) + access (or (is-vip? session) + (not (:admin-only msg)))] + (cond (not msg) (resp-error "NO_MSG") + (not access) (resp-error "NO_MSG") + (not tag) (resp-error "NO_TAG") + :else (if (add-tag session msg tag) + (resp-success "OK") + (resp-error "TAG_EXISTS_ALREADY_OR_SOMETHING_ELSE_IS_FUCKED")))) + (resp-error "NO_USER"))) (defn remove-tag [user-id message-id tag] (let [query "user_id = ? AND message_id = ? AND lower(tag) = ?"] @@ -962,14 +984,14 @@ FROM users u (POST "/reset" (reset-account! session params)) ;; Admin stuff (should be own route?) - (GET "/debug" (debug-page session flash)) + (GET "/debug" (debug-page session flash)) (POST "/debug" (debug-commmand! session params)) - (GET "/mutes" (show-mutes session)) + (GET "/mutes" (show-mutes session)) (POST "/mute" (mute! session params)) (POST "/cancel-mute" (handle-cancel-mute! session params)) - (GET "/feed-test" (feed-test-page session)) + (GET "/feed-test" (feed-test-page session)) (POST "/feed-test" (feed-test session params)) - (GET "/profile-test/:t" (profile session "ryder" "0" (params :t))) + (GET "/profile-test/:t" (profile session "ryder" "0" (params :t))) ;; Footer pages (GET "/about_us" (serve-template "about_us" session)) diff --git a/src/tags.clj b/src/tags.clj index 3878a18..7fdc0cd 100644 --- a/src/tags.clj +++ b/src/tags.clj @@ -1,5 +1,6 @@ (ns tags - (:import java.lang.System) + (:import java.lang.System + java.util.Date) (:use clojure.contrib.sql clojure.contrib.def clojure.contrib.json.write @@ -7,6 +8,10 @@ compojure utils)) +(defn validate-tag [tag] + (if (re-matches #"[A-Za-z]{3,12}" tag) + (.toLowerCase tag))) + ; save all spaces in tags as dashes? (defn normalize-tag-for-db [tag] (str tag)) ; (.replace tag " " "-")) @@ -224,9 +229,20 @@ (map parse-tags-from-row-as-tag-map rows))) - - - - - - \ No newline at end of file +(def fav-map (ref {})) + +(defn filter-old-favs [fs] + (let [threshold (new Date (ms-in-future -60000))] + (filter #(.after (:added %) threshold) + fs))) + +(defn insert-fav-notification! [to-nick from-nick from-avatar msg] + (dosync + (let [favs (ensure fav-map) + cur-favs (filter-old-favs (or (favs to-nick) [])) + fav {:from from-nick + :avatar from-avatar + :msg msg + :added (new Date)} + new-fs (conj cur-favs fav)] + (alter fav-map assoc to-nick new-fs)))) \ No newline at end of file diff --git a/src/user.clj b/src/user.clj index d105e29..387a7ad 100644 --- a/src/user.clj +++ b/src/user.clj @@ -2,6 +2,12 @@ (:use compojure utils)) +(defstruct user-struct :nick :user_id :avatar :last-seen) + +(defn user-struct-from-session [session] + (struct user-struct (session :nick) (session :user_id) (session :avatar) + (System/currentTimeMillis))) + (def *nick-regex* #"^[A-Za-z0-9\-_âˆb˚†]*$") (defn is-invalid-nick? [n] diff --git a/static/css/dump.css b/static/css/dump.css index 0d3538e..f6e4bce 100755 --- a/static/css/dump.css +++ b/static/css/dump.css @@ -360,6 +360,48 @@ border:1px solid blue; } +#favbox { + display: none; + overflow-x: hidden; + overflow-y:auto; + max-height: 300px; + margin: 0px; + position: absolute; + padding: 5px; + bottom:25px; + min-width: 210px; + width:11%; + float:right; + right: 4.5%; + font-family: Arial, Helvetica, sans-serif; + font-size: 14px; + font-weight:420; + border-top-left-radius:5px; + border-top-right-radius:5px; + -webkit-border-top-left-radius:5px; + background-color:#FFF; + -webkit-border-top-right-radius:5px; + -moz-border-radius-topleft:5px; + -moz-border-radius-topright:5px; + border-bottom-left-radius:5px; + border-bottom-right-radius:5px; + -webkit-border-bottom-left-radius:5px; + -webkit-border-bottom-right-radius:5px; + -moz-border-radius-bottomleft:5px; + -moz-border-radius-bottomright:5px; + border-right:2px solid #c8cbce; + border-bottom:2px solid #c8cbce; + + box-shadow: 3px 4px 4px #c8cbce; + -webkit-box-shadow: 3px 4px 4px #c8cbce; + -moz-box-shadow: 3px 3px 4px #c8cbce; + filter: progid:DXImageTransform.Microsoft.dropShadow(color=#c8cbce, offX=3, offY=4, positive=true); + text-overflow:ellipsis; + /* opacity:0.87; */ + z-index:18; + text-align: left; +} + #userList { overflow-x: hidden; overflow-y:auto; diff --git a/static/js/pichat.js b/static/js/pichat.js index 93e2f05..e884c15 100644 --- a/static/js/pichat.js +++ b/static/js/pichat.js @@ -202,6 +202,36 @@ function buildUserDiv(user) { } } +// Favs + +function buildFav(f) { + var h = '
' + + '' + + '' + f.from + '' + + ' just faved you!' + + '
'; + return $(h); +} + +function removeFavAndHideBox() { + $(this).remove(); + if ($('#favbox').children().length == 0) + $('#favbox').hide(); +} + +function showFav(f) { + $('#favbox').show(); + buildFav(f).appendTo('#favbox').fadeOut(3000, removeFavAndHideBox); +} + +function updateFavs(fs) { + if (fs.length == 0) + return; + $('#favbox').show(); + $(fs).each(function(i, f) { showFav(f) }); +} + + // Growl function buildGrowlDataAndPopDatShit(msg) { @@ -318,8 +348,7 @@ function flattenUserJson(users) { return s; } -function updateUI(msgs, users) { - +function updateUI(msgs, users, favs) { if (window['growlize'] && msgs && msgs.length > 0) { $.map(msgs, buildGrowlDataAndPopDatShit) } else if (msgs && msgs.length > 0) { @@ -332,6 +361,7 @@ function updateUI(msgs, users) { } cache.userlist = flattened } + updateFavs(favs); } function sortUsersByAlpha(a, b){ @@ -365,7 +395,7 @@ function refresh() { var messages = $.grep( json.messages, function(m) { return !isDuplicateMessage(m) }); - updateUI(messages, json.users); + updateUI(messages, json.users, json.favs); if (typeof UnseenMsgCounter !== 'undefined' && !HasFocus) { UnseenMsgCounter += messages.length; } diff --git a/template/chat.st b/template/chat.st index fe0abc0..a08138f 100644 --- a/template/chat.st +++ b/template/chat.st @@ -78,19 +78,20 @@ $endif$
-
- $users: { u | - +
$messages: { m |
-- cgit v1.2.3-70-g09d2