root.go

  1// SPDX-FileCopyrightText: 2022 Amolith <amolith@secluded.site>
  2//
  3// SPDX-License-Identifier: BSD-2-Clause
  4
  5package main
  6
  7import (
  8	"io"
  9	"log"
 10	"net/http"
 11	"net/url"
 12	"strconv"
 13	"strings"
 14
 15	"github.com/dchest/uniuri"
 16	"github.com/dgraph-io/badger/v3"
 17)
 18
 19func (m model) root(writer http.ResponseWriter, request *http.Request) {
 20	path := request.URL.Path
 21	if path != "/" {
 22		destinationKey := strings.TrimPrefix(path, "/")
 23		err := m.database.View(func(txn *badger.Txn) error {
 24			destinationEntry, err := txn.Get([]byte(destinationKey))
 25			if err == nil {
 26				destinationValue, err := destinationEntry.ValueCopy(nil)
 27				if err != nil {
 28					return err
 29				}
 30				log.Println("Redirecting visitor to \"" + string(destinationValue) + "\"")
 31				http.Redirect(writer, request, string(destinationValue), 302)
 32			}
 33			return err
 34		})
 35		if err != nil {
 36			_, err = io.WriteString(writer, string(err.Error()))
 37			if err != nil {
 38				log.Println(err)
 39			}
 40		}
 41		return
 42	}
 43
 44	cookie, err := request.Cookie("access_token")
 45	if err != nil || cookie.Value != m.AccessToken {
 46		_, err = io.WriteString(writer, unauthenticated())
 47		if err != nil {
 48			log.Println(err)
 49		}
 50		return
 51	}
 52
 53	query := request.URL.Query()
 54
 55	action := query.Get("action")
 56	if len(action) == 0 {
 57		start := query.Get("start")
 58		end := query.Get("end")
 59
 60		if len(start) > 0 && len(end) > 0 {
 61			http.Error(writer, "Submit either start OR end parameter, not both", 400)
 62		}
 63
 64		countQuery := query.Get("count")
 65		var count int
 66		if len(countQuery) == 0 {
 67			count = 20
 68		} else {
 69			count, err = strconv.Atoi(countQuery)
 70			if err != nil {
 71				http.Error(writer, err.Error(), 400)
 72				return
 73			}
 74		}
 75
 76		links, err := m.read(start, end, count)
 77		if err != nil {
 78			http.Error(writer, err.Error(), 400)
 79			return
 80		}
 81
 82		_, err = io.WriteString(writer, m.authenticated(links))
 83		if err != nil {
 84			log.Println(err)
 85		}
 86	}
 87
 88	destination := query.Get("url")
 89	name := query.Get("name")
 90	oldName := query.Get("oldName")
 91
 92	var message string
 93
 94	if action == "create" {
 95		if len(destination) == 0 {
 96			message = "URL field is required"
 97			http.Redirect(writer, request, "/?message="+message, 302)
 98			return
 99		}
100
101		if len(name) == 0 {
102			name = uniuri.NewLen(4)
103			for m.nameExists(name) {
104				name = uniuri.NewLen(4)
105				log.Println("Generated new name:", name)
106			}
107		} else if m.nameExists(name) {
108			http.Error(writer, "406 Not Acceptable: A shortened URL with this name already exists", 406)
109			message = "A shortened URL with this name already exists"
110			http.Redirect(writer, request, "/?message="+message, 302)
111			return
112		}
113
114		message = url.QueryEscape(m.create(name, destination))
115		http.Redirect(writer, request, "/?message="+message, 302)
116		return
117	}
118
119	if action == "edit" {
120		_, err = io.WriteString(writer, m.edit(name, destination))
121		if err != nil {
122			log.Println(err)
123		}
124	}
125
126	if action == "update" {
127		if len(destination) == 0 {
128			message = "URL field is required"
129			http.Redirect(writer, request, "/?message="+message, 302)
130			return
131		}
132
133		if len(name) == 0 {
134			message = "Name field is required"
135			http.Redirect(writer, request, "/?message="+message, 302)
136			return
137		}
138
139		if len(oldName) == 0 {
140			message = "oldName field is required"
141			http.Redirect(writer, request, "/?message="+message, 302)
142			return
143		}
144
145		if len(name) != 0 && oldName != name {
146			if m.nameExists(name) {
147				message = "A shortened URL with this name already exists"
148				http.Redirect(writer, request, "/?message="+message, 302)
149				return
150			}
151		}
152
153		message := url.QueryEscape(m.update(name, destination, oldName))
154		http.Redirect(writer, request, "/?message="+message, 302)
155	}
156
157	if action == "delete" {
158		if len(name) == 0 {
159			message = "Name field is required"
160			http.Redirect(writer, request, "/?message="+message, 302)
161		}
162		message := url.QueryEscape(m.delete(name))
163		log.Println(message)
164		http.Redirect(writer, request, "/?message="+message, 302)
165	}
166}