Skip to content

Commit

Permalink
Split clojars.db into seperate files. Removed the old sqlite backend.
Browse files Browse the repository at this point in the history
  • Loading branch information
ato committed Nov 26, 2009
1 parent e9e24c7 commit bfaa9ed
Show file tree
Hide file tree
Showing 11 changed files with 315 additions and 454 deletions.
1 change: 0 additions & 1 deletion project.clj
Expand Up @@ -10,7 +10,6 @@

[org.clojars.ato/compojure "0.3.1"]
[org.clojars.ato/nailgun "0.7.1"]
[org.xerial/sqlite-jdbc "3.6.17"]

[org.clojars.ato/clutch "0.1.0-SNAPSHOT"]
[org.clojars.ato/scriptjure "0.1.0-SNAPSHOT"]])
5 changes: 2 additions & 3 deletions src/clojars/config.clj
@@ -1,5 +1,4 @@
{:db {:classname "org.sqlite.JDBC"
:subprotocol "sqlite"
:subname "/home/clojars/data/db"}
{:db {:name "clojars"
:language "clojure"}
:key-file "/home/clojars/data/auth_keys"
:repo "/home/clojars/repo"}
265 changes: 47 additions & 218 deletions src/clojars/db.clj
@@ -1,222 +1,51 @@
;;; TODO: split into seperate files

(ns clojars.db
(:use [clojars :only [config]]
clojure.contrib.duck-streams
clojure.contrib.sql
[clojure.contrib.str-utils2 :only [join]]
[clojure.contrib.json.write :only [print-json]]
[com.ashafa.clutch :exclude [config]]
[com.reasonr.scriptjure :only (js)])
(:import java.security.MessageDigest
java.util.Date
java.io.File
java.text.SimpleDateFormat))

(def *db* "clojars") ; TODO: move to config

(def ssh-options "no-agent-forwarding,no-port-forwarding,no-pty,no-X11-forwarding")

(def *reserved-names*
#{"clojure" "clojars" "clojar" "register" "login"
"pages" "logout" "password" "username" "user"
"repo" "repos" "jar" "jars" "about" "help" "doc"
"docs" "pages" "images" "js" "css" "maven" "api"
"download" "create" "new" "upload" "contact" "terms"
"group" "groups" "browse" "status" "blog" "search"
"email" "welcome" "devel" "development" "test" "testing"
"prod" "production" "admin" "administrator" "root"
"webmaster" "profile" "dashboard" "settings" "options"
"index" "files"})



(let [chars (map char
(mapcat (fn [[x y]] (range (int x) (inc (int y))))
[[\a \z] [\A \Z] [\0 \9]]))]
(defn rand-string
"Generates a random string of [A-z0-9] of length n."
[n]
(apply str (take n (map #(nth chars %)
(repeatedly #(rand (count chars))))))))

(defn gen-salt []
(rand-string 16))



(defn db-middleware
[handler]
(fn [request]
(with-connection (:db config) (handler request))))

(defmacro with-db
[& body]
`(with-connection (:db config)
~@body))

(defn sha1 [& s]
(when-let [s (seq s)]
(let [md (MessageDigest/getInstance "SHA")]
(.update md (.getBytes (apply str s)))
(format "%040x" (java.math.BigInteger. 1 (.digest md))))))

;;
;; Couch utils
;;

;;
;; Users
;;

(defview *db* :users :all [doc]
(if (== doc.type "users")
(emit nil doc)))

(defn find-user [username]
(get-view *db* :users :all {:startkey username}))
(find-user "ato")

;;
;;
;;

(defn find-user [username]
(with-query-results rs ["select * from users where user = ?" username]
(first rs)))

(defn find-groups [username]
(with-query-results rs ["select * from groups where user = ?" username]
(doall (map :name rs))))

(defn group-members [group]
(with-query-results rs ["select * from groups where name like ?" group]
(doall (map :user rs))))

(defn auth-user [user pass]
(with-query-results rs
["select * from users where (user = ? or email = ?)" user user]
(first (filter #(= (:password %) (sha1 (:salt %) pass)) rs))))

(defn jars-by-user [user]
(with-query-results rs [(str "select * from jars where user = ? "
"group by group_name, jar_name") user]
(vec rs)))

(defn jars-by-group [group]
(with-query-results rs [(str "select * from jars where "
"group_name = ? group by jar_name")
group]
(vec rs)))

(defn recent-jars []
(with-query-results rs
[(str "select * from jars group by group_name, jar_name "
"order by created desc limit 5")]
(vec rs)))

(defn find-canon-jar [jarname]
(with-query-results rs
[(str "select * from jars where "
"jar_name = ? and group_name = ? "
"order by created desc limit 1")
jarname jarname]
(first rs)))

(defn find-jar
([jarname]
(with-query-results rs [(str "select * from jars where "
"jar_name = ?") jarname]
(first rs)))
([group jarname]
(with-query-results rs [(str "select * from jars where group_name = ? and "
"jar_name = ? order by created desc "
"limit 1") group jarname]
(first rs))))


(defn add-user [email username password ssh-key]
(let [salt (gen-salt)]
(document-create
*db*
{:type :user
:username username
:email email
:password (sha1 salt password)
:salt salt
:ssh-keys [ssh-key]
:created (Date.)
:groups [(str "org.clojars." username)]})))

(defn update-user [account email user password ssh-key]
(let [salt (rand-string 16)]
(update-values
:users ["user=?" account]
{:email email
:user user
:salt salt
:password (sha1 salt password)
:ssh_key ssh-key
:groups [(str "org.clojars." user)]})
(write-key-file (:key-file config))))

(defn add-member [group user]
(insert-records :groups
{:name group
:user user}))

(defn check-and-add-group [account group jar]
(when-not (re-matches #"^[a-z0-9-_.]+$" group)
(throw (Exception. (str "Group names must consist of lowercase "
"letters, numbers, hyphens, underscores "
"and full-stops."))))
(let [members (group-members group)]
(if (empty? members)
(if (or (find-user group) (*reserved-names* group))
(throw (Exception. (str "The group name " group " is already taken.")))
(add-member group account))
(when-not (some #{account} members)
(throw (Exception. (str "You don't have access to the "
group " group.")))))))

(defn add-jar [account jarmap & [check-only]]
(when-not (re-matches #"^[a-z0-9-_.]+$" (:name jarmap))
(throw (Exception. (str "Jar names must consist solely of lowercase "
"letters, numbers, hyphens and underscores."))))

(with-connection (:db config)
(transaction
(when check-only (set-rollback-only))
(check-and-add-group account (:group jarmap) (:name jarmap))
(insert-records
:jars
{:group_name (:group jarmap)
:jar_name (:name jarmap)
:version (:version jarmap)
:user account
:created (Date.)
:description (:description jarmap)
:homepage (:homepage jarmap)
:authors (join ", " (map #(.replace % "," "")
(:authors jarmap)))}))))

(defn search-jars [query & [offset]]
;; TODO make search less stupid, figure out some relevance ranking
;; scheme, do stopwords etc.
(with-query-results rs
[(str "select jar_name, group_name from search where "
"content match ?"
"limit 50 "
"offset ?")
query
(or offset 0)]
;; TODO: do something less stupidly slow
(vec (map #(find-jar (:group_name %) (:jar_name %)) rs))))
"CouchDB database backend"
(:use [clojure.contrib.ns-utils :only [immigrate]])
(:require (clojars.db utils users jars groups)))

(immigrate 'clojars.db.utils
'clojars.db.users
'clojars.db.jars
'clojars.db.groups)


(defn init-db []
(init-users-view)
(init-jars-view))

(comment
(with-connection (:db config) (add-jar "atotx" {:name "test3" :group "test3" :version "1.0"
:description "An dog awesome and non-existent test jar."
:homepage "http://clojars.org/"
:authors ["Alex Osborne"
"a little fish"]}))
(with-connection (:db config) (find-user "atotx"))
)
(conj {} {1 2})
(with-db db (doall (view-seq "users" :all {})))




(def db {:name "clojars-test"
:language "clojure"})
(with-db db
(init-db)

(find-user "atox")
)

(lazy-seq (concat [1 2] [3 4]))



(with-db db
(get-view "users" :all))

(= [1 2 3] '(1 2 3))

(update-document)

(with-db db
(create-document
{:type "user"
:username "atox"}))

(ad-hoc-view
(with-clj-view-server
(fn [doc] [nil doc]))))
26 changes: 26 additions & 0 deletions src/clojars/db/groups.clj
@@ -0,0 +1,26 @@
(ns clojars.db.groups
(:use (clojars.db utils users)
com.ashafa.clutch))

(defn group-members [group]
(map :value (:rows (get-view "users" :by-group {:key group}))))

(defn add-member [group username]
(let [user (find-user username)]
(assert user)
(when-not (some #{group} (:groups user))
(update-document user {:groups (conj (:groups user) group)}))))

(defn check-and-add-group [account group jar]
(when-not (re-matches #"^[a-z0-9_.-]+$" group)
(throw (Exception. (str "Group names must consist of lowercase "
"letters, numbers, hyphens, underscores "
"and full-stops."))))
(let [members (group-members group)]
(if (empty? members)
(if (or (find-user group) (*reserved-names* group))
(throw (Exception. (str "The group name " group " is already taken.")))
(add-member group account))
(when-not (some #{account} members)
(throw (Exception. (str "You don't have access to the "
group " group. Only " (vec members))))))))
63 changes: 63 additions & 0 deletions src/clojars/db/jars.clj
@@ -0,0 +1,63 @@
(ns clojars.db.jars
(:use (clojars.db utils groups)
com.ashafa.clutch)
(:import java.util.Date))

(defn all-jars []
(map second (view-seq "jars" :all)))

(defn recent-jars []
(map second (view-seq "jars" :by-created
{:descending true})))

(defn jars-by-user [username]
(map second (view-seq "jars" :by-user {:key username})))

(defn jars-by-group [group]
(map second (view-seq "jars" :by-group {:key group})))

(defn add-jar [account jarmap & [check-only]]
(when-not (re-matches #"^[a-z0-9_.-]+$" (:name jarmap))
(throw (Exception. (str "Jar names must consist of lowercase "
"letters, numbers, hyphens and underscores."))))

(when-not (re-matches #"^[a-zA-Z0-9_.-]+$" (:version jarmap))
(throw (Exception.
(str "Versions must consist only of "
"letters, numbers, hyphens, underscores and dots."))))

(check-and-add-group account (:group jarmap) (:name jarmap))

(create-document
(assoc jarmap
:type "jar"
:user account
:created (Date.))))

(defn init-jars-view []
(when-let [doc (get-document "_design/jars")]
(delete-document doc))

(create-clj-view
"jars" "all"
(fn [doc]
(when (= (doc :type) "jar")
[[nil doc]])))

(create-clj-view
"jars" "by-user"
(fn [doc]
(when (= (doc :type) "jar")
[[(:user doc) doc]])))

(create-clj-view
"jars" "by-group"
(fn [doc]
(when (= (doc :type) "jar")
[[(:group doc) doc]])))

(create-clj-view
"jars" "by-created"
(fn [doc]
(when (= (doc :type) "jar")
[[(:created doc) doc]]))))

0 comments on commit bfaa9ed

Please sign in to comment.