commit 822df7fe35285655fd2d1659a6fcce1368509a5c Author: Adalricus Ovicula Date: Sun Feb 2 16:44:51 2020 +0530 Initial Commit diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7ed2d04 --- /dev/null +++ b/LICENSE @@ -0,0 +1,13 @@ +Copyright (c) 2020, Adalricus Ovicula + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/README b/README new file mode 100644 index 0000000..152c5c9 --- /dev/null +++ b/README @@ -0,0 +1,12 @@ +Cortris +======= + +Cortris is a simple url shortener + +Database Structure +------------------ +Database Name: cortris + +shortURL: Not Null +time: Not Null +url: Primary Key & Not Null diff --git a/main.go b/main.go new file mode 100644 index 0000000..860166a --- /dev/null +++ b/main.go @@ -0,0 +1,137 @@ +// Cortris is a simple url shortener + +// Copyright (c) 2020, Adalricus Ovicula +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +package main + +import ( + "database/sql" + "html/template" + "log" + "math/rand" + "net/http" + "time" + + "github.com/gorilla/mux" + _ "github.com/mattn/go-sqlite3" +) + +func main() { + rand.Seed(time.Now().UnixNano()) + r := mux.NewRouter() + r.HandleFunc("/", indexH).Methods("GET") + r.HandleFunc("/short/", sURLH).Methods("POST") + r.HandleFunc("/{sURL}/", urlH).Methods("GET") + + r.PathPrefix("/static/"). + Handler(http.FileServer(http.Dir("./"))) + + log.Println("listening on port 8080...") + srv := &http.Server{ + Handler: r, + Addr: "127.0.0.1:8080", + WriteTimeout: 8 * time.Second, + ReadTimeout: 8 * time.Second, + } + log.Fatal(srv.ListenAndServe()) +} + +type shortP struct { + ShortURL string + URL string +} + +func indexH(w http.ResponseWriter, r *http.Request) { + t, _ := template.ParseFiles("templates/index.html") + t.Execute(w, nil) +} + +// This is the POST endpoint +func sURLH(w http.ResponseWriter, r *http.Request) { + if err := r.ParseForm(); err != nil { + errChk(err) + } + + dbL := "/home/adalricus/projects/db/adalricus.db" + url := r.FormValue("url") + db, err := sql.Open("sqlite3", dbL) + errChk(err) + defer db.Close() + + // Checks if url is already in the database + stmt, err := db.Prepare("SELECT shortURL FROM cortris WHERE url = ?") + errChk(err) + defer stmt.Close() + + var shortURL string + err = stmt.QueryRow(url).Scan(&shortURL) + + // If short url doesn't exist then create it + if len(shortURL) == 0 { + shortURL = randS(8) + tx, err := db.Begin() + errChk(err) + + stmt, err := tx.Prepare("INSERT INTO cortris(url, shortURL, time) VALUES(?, ?, ?)") + errChk(err) + + defer stmt.Close() + _, err = stmt.Exec(url, shortURL, time.Now().UTC()) + errChk(err) + + tx.Commit() + } + + p := shortP{ + ShortURL: shortURL, + URL: url} + t, _ := template.ParseFiles("templates/short.html") + t.Execute(w, p) +} + +// This handles short urls +func urlH(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + shortURL := vars["sURL"] + + dbL := "/home/adalricus/projects/db/adalricus.db" + db, err := sql.Open("sqlite3", dbL) + errChk(err) + defer db.Close() + stmt, err := db.Prepare("SELECT url FROM cortris WHERE shortURL = ?") + errChk(err) + + var url string + err = stmt.QueryRow(shortURL).Scan(&url) + + if len(url) != 0 { + http.Redirect(w, r, url, http.StatusSeeOther) + } +} + +func errChk(err error) { + if err != nil { + log.Fatal(err) + } +} + +func randS(n int) string { + var alphaNum = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") + b := make([]rune, n) + for i := range b { + b[i] = alphaNum[rand.Intn(len(alphaNum))] + } + return string(b) +} diff --git a/static/favicon.png b/static/favicon.png new file mode 100644 index 0000000..b64d71b Binary files /dev/null and b/static/favicon.png differ diff --git a/static/style.css b/static/style.css new file mode 100644 index 0000000..1b43d3e --- /dev/null +++ b/static/style.css @@ -0,0 +1,136 @@ +html { + font-family: "Fira Sans"; + line-height: 1.5; + background-color: #282a2e; + color: #c5c8c6; +} +body { + margin: auto; + padding: 0; + max-width: 80ch; +} +header, +main, +footer { + margin: 1rem; + padding: 0.5rem 1rem; +} +main { + background-color: #1d1f21; +} +footer { + text-align: right; +} +blockquote { + padding: .5rem 1rem; + margin: .8rem 0; + color: #c5c8c6; + border-left: .25rem solid #282a2e; +} +@media (min-width: 30em) { + blockquote { + padding-right: 5rem; + padding-left: 1.25rem; + } +} +img { + display: block; + margin: auto; + border-radius: 5px; + max-width: 100%; +} +code { + padding: .25em .5em; + font-size: 85%; + background-color: #282a2e; + border-radius: 0; +} +pre { + display: block; + margin-top: 0; + margin-bottom: 1rem; + padding: 1rem; + font-size: .8rem; + line-height: 1.4; + white-space: pre; + white-space: pre-wrap; + word-break: break-all; + word-wrap: break-word; + background-color: #282a2e; +} +pre code { + padding: 0; + font-size: 100%; + color: inherit; + background-color: transparent; +} +a { + color: #81a2be; + text-decoration: none; + border-bottom: 0.1rem dashed #81a2be; +} +a:visited { + color: #b294bb; +} +a:hover, +a:focus { + border-bottom: 0.2rem solid #81a2be; +} +h1, h2, h3, h4, h5, h6 { + margin-bottom: .5rem; + font-weight: 400; + line-height: 1.25; +} +h1 { + font-size: 2rem; + border-bottom: 0.16rem solid #cc6666; +} +h2 { + margin-top: 1rem; + font-size: 1.5rem; +} +h3 { + margin-top: 1.5rem; + font-size: 1.25rem; +} +h4, +h5, +h6 { + margin-top: 1rem; + font-size: 1rem; +} +ul, ol, dl { + margin: 1rem 0; +} +hr { + color: #cc6666; +} +table { + margin-bottom: 1rem; + width: 100%; + border: 1px solid #282a2e; + border-collapse: collapse; +} +td, +th { + padding: .25rem .5rem; + border: 1px solid #282a2e; +} +tbody tr:nth-child(odd) td, +tbody tr:nth-child(odd) th { + background-color: #282a2e; +} +button, +input, +select, +textarea { + background-color: #282a2e; + color: #c5c8c6; + padding: 0.2rem 0.8rem; +} +textarea { + width: 80%; +} +textarea { + resize: vertical; +} diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..d4cd9c6 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,35 @@ + + + + Cortris + + + + + +
+ index + ⁘ ⁘ + cortris +
+
+

Cortris

+

+ Cortris is a simple url shortener +

+
+

URL to shorten

+ + +
+
+
+
+

+ Copyright © 2020 Adalricus Ovicula
+ Cortris is licensed under the ISC License. + +

+
+ + diff --git a/templates/short.html b/templates/short.html new file mode 100644 index 0000000..1b4369f --- /dev/null +++ b/templates/short.html @@ -0,0 +1,36 @@ + + + + Cortris + + + + + +
+ index + ⁘ ⁘ + cortris +
+
+

Cortris

+ +
+

URL to shorten

+ + +
+
+
+ + +