(defproject notes "0.1.0-SNAPSHOT" :description " " :min-lein-version "2.0.0" :dependencies [; -, Clojure ; [org.clojure/clojure "1.6.0"] ; GET POST [compojure "1.3.1"] ; (middleware) ; [ring/ring-defaults "0.1.5"] ; [selmer "0.8.2"] ; Monger [com.novemberain/monger "2.0.1"] ; [clojure.joda-time "0.6.0"]] ; - ; , ; Ring' - Jetty :plugins [[lein-ring "0.8.13"]] ; Ring ; app ; :ring {:handler notes.handler/app} :profiles {:dev {:dependencies [[javax.servlet/servlet-api "2.5"] [ring-mock "0.1.5"]]}})
(ns notes.handler (:require ; [notes.routes :refer [notes-routes]] ; middleware [ring.middleware.defaults :refer [wrap-defaults site-defaults]])) ; middleware (def app (wrap-defaults notes-routes site-defaults))
(ns notes.routes (:require ; [compojure.core :refer [defroutes GET POST]] [compojure.route :as route] ; [notes.controllers :as c] ; [notes.views :as v] ; [notes.db :as db])) ; (defroutes notes-routes ; (GET "/note/:id" [id] ; ObjectId ; (let [note (db/get-note id)] (v/note note))) ; ObjectId (GET "/delete/:id" [id] (c/delete id)) ; (POST "/edit/:id" request (-> c/edit)) ; ; , ; ObjectId ; , ; . (GET "/edit/:id" [id] ; ObjectId ; (let [note (db/get-note id)] (v/edit note))) ; (POST "/create" ; ; [title text], ; request ; request ; ; : (create-controller request) (-> c/create)) ; (GET "/create" [] (v/create)) ; (GET "/" [] ; ; fn (let [notes (db/get-notes)] (v/index notes))) ; 404 (route/not-found " "))
(ns notes.controllers (:require ; [ring.util.response :refer [redirect]] ; [notes.db :as db])) (defn delete " " [id] (do (db/remove-note id) (redirect "/"))) (defn edit " " [request] ; (let [note-id (get-in request [:form-params "id"]) note {:title (get-in request [:form-params "title"]) :text (get-in request [:form-params "text"])}] ; (if (and (not-empty (:title note)) (not-empty (:text note))) ; ; ; ; (do (db/update-note note-id note) (redirect "/")) ; " "))) (defn create " " [request] ; ; ; hash-map ; ( ) (let [note {:title (get-in request [:form-params "title"]) :text (get-in request [:form-params "text"])}] ; (if (and (not-empty (:title note)) (not-empty (:text note))) ; ; ; ; (do (db/create-note note) (redirect "/")) ; " ")))
(ns notes.db (:require ; Monger monger.joda-time ; [monger.core :as mg] [monger.collection :as m] [monger.operators :refer :all] ; [joda-time :as t]) ; Java (:import org.bson.types.ObjectId org.joda.time.DateTimeZone)) ; (DateTimeZone/setDefault DateTimeZone/UTC) ; (defonce db (let [uri "mongodb://127.0.0.1/notes_db" {:keys [db]} (mg/connect-via-uri uri)] db)) ; (defn- date-time " " [] (t/date-time)) (defn remove-note " ObjectId" [id] ; ObjectId (let [id (ObjectId. id)] (m/remove-by-id db "notes" id))) (defn update-note " ObjectId" [id note] ; ObjectId (let [id (ObjectId. id)] ; $set ; ; ; ; hash-map + ; ; . ; - ; ObjectId ; update-by-id, ; ; (m/update db "notes" {:id id} ; ; {$set (assoc note :created (date-time))}))) (defn get-note " ObjectId" [id] ; :_id ; ; ObjectId ; , ; ObjectId (let [id (ObjectId. id)] ; hash-map (m/find-map-by-id db "notes" id))) (defn get-notes " " [] ; Find-maps ; hash-map (m/find-maps db "notes")) (defn create-note " " ; ; hash-map c : ; {:title "" :text ""} [note] ; Monger ObjectId ; ; (let [object-id (ObjectId.)] ; hash-map ; , ; ObjectId ; (m/insert db "notes" (assoc note :_id object-id :created (date-time)))))
(ns notes.views (:require ; "" [selmer.parser :as parser] [selmer.filters :as filters] ; [joda-time :as t] ; HTTP [ring.util.response :refer [content-type response]] ; CSRF [ring.util.anti-forgery :refer [anti-forgery-field]])) ; Selmer (parser/set-resource-path! (clojure.java.io/resource "templates")) ; - (defn format-date-and-time " " [date] (let [formatter (t/formatter "yyyy-MM-dd H:m:s" :date-time)] (when date (t/print formatter date)))) ; (filters/add-filter! :format-datetime (fn [content] [:safe (format-date-and-time content)])) ; ; anti-forgery (parser/add-tag! :csrf-field (fn [_ _] (anti-forgery-field))) (defn render [template & [params]] " html " (-> template (parser/render-file ; ; ; (assoc params :title " " :page (str template))) ; HTTP response (content-type "text/html; charset=utf-8"))) (defn note " " [note] (render "note.html" ; {:note note})) (defn edit " " [note] (render "edit.html" ; {:note note})) (defn create " " [] (render "create.html")) (defn index " . " [notes] (render "index.html" ; ; notes false {:notes (if (not-empty notes) notes false)}))
<!DOCTYPE html> <html> <head> <META http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>{{title}}</title> </head> <body> <ul> <li> {% ifequal page "index.html" %} <strong> </strong> {% else %} <a href="/"> </a> {% endifequal %} </li> <li> {% ifequal page "create.html" %} <strong> </strong> {% else %} <a href="/create"> </a> {% endifequal %} </li> </ul> {% block content %} {% endblock %} </body> </html>
{% extends "base.html" %} {% block content %} <h1> </h1> <form action="POST"> {% csrf-field %} <p> <label></label><br> <input type="text" name="title" placeholder=""> </p> <p> <label></label><br> <textarea name="text"></textarea> </p> <input type="submit" value=""> </form> {% endblock %}
{% extends "base.html" %} {% block content %} <h1> </h1> <form method="POST"> {% csrf-field %} <input type="hidden" name="id" value="{{note._id}}"> <p> <label></label><br> <input type="text" name="title" value="{{note.title}}"> </p> <p> <label></label><br> <textarea name="text">{{note.text}}</textarea> </p> <input type="submit" value=""> </form> {% endblock %}
{% extends "base.html" %} {% block content %} <h1>{{note.title}}</h1> <small>{{note.created|format-datetime}}</small> <p>{{note.text}}</p> {% endblock %}
{% extends "base.html" %} {% block content %} <h1></h1> {% if notes %} <ul> {% for note in notes %} <li> <h4><a href="/note/{{note._id}}">{{note.title}}</a></h4> <small>{{note.created|format-datetime}}</small> <hr> <a href="/edit/{{note._id}}"></a> | <a href="/delete/{{note._id}}"></a> </li> {% endfor %} </ul> {% else %} <strong> </strong> {% endif %} {% endblock %}
Source: https://habr.com/ru/post/263131/