Initial Commit
This commit is contained in:
commit
822df7fe35
|
@ -0,0 +1,13 @@
|
|||
Copyright (c) 2020, Adalricus Ovicula <adalricus@inventati.org>
|
||||
|
||||
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.
|
|
@ -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
|
|
@ -0,0 +1,137 @@
|
|||
// Cortris is a simple url shortener
|
||||
|
||||
// Copyright (c) 2020, Adalricus Ovicula <adalricus@inventati.org>
|
||||
//
|
||||
// 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)
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Cortris</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link href="./static/style.css" rel="stylesheet">
|
||||
<link rel="icon" href="./static/favicon.png" type="image/png">
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<a href="./">index</a>
|
||||
⁘ ⁘
|
||||
cortris
|
||||
</header>
|
||||
<main>
|
||||
<h1>Cortris</h1>
|
||||
<p>
|
||||
Cortris is a simple url shortener
|
||||
</p>
|
||||
<form action="./short/" method="post">
|
||||
<h3>URL to shorten</h3>
|
||||
<input type="text" maxlength="256" name="url" required>
|
||||
<input type="submit" name="submit" value="Go!">
|
||||
</form>
|
||||
<br>
|
||||
</main>
|
||||
<footer>
|
||||
<p>
|
||||
Copyright © 2020 Adalricus Ovicula<br>
|
||||
Cortris is licensed under the ISC License.
|
||||
</a>
|
||||
</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,36 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Cortris</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link href="../static/style.css" rel="stylesheet">
|
||||
<link rel="icon" href="../static/favicon.png" type="image/png">
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<a href="../">index</a>
|
||||
⁘ ⁘
|
||||
cortris
|
||||
</header>
|
||||
<main>
|
||||
<h1>Cortris</h1>
|
||||
<ul>
|
||||
<li>Short URL: <a href="../{{ .ShortURL }}/">{{ .ShortURL }}</a></li>
|
||||
<li>Original URL: {{ .URL }}</li>
|
||||
</ul>
|
||||
<form action="./" method="post">
|
||||
<h3>URL to shorten</h3>
|
||||
<input type="text" maxlength="256" name="url" required>
|
||||
<input type="submit" name="submit" value="Go!">
|
||||
</form>
|
||||
<br>
|
||||
</main>
|
||||
<footer>
|
||||
<p>
|
||||
Copyright © 2020 Adalricus Ovicula<br>
|
||||
Cortris is licensed under the ISC License.
|
||||
</a>
|
||||
</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue