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		if len(links) == 0 {
 83			links, err = m.read("", "", count)
 84			if err != nil {
 85				http.Error(writer, err.Error(), 400)
 86				return
 87			}
 88		}
 89
 90		_, err = io.WriteString(writer, m.authenticated(links))
 91		if err != nil {
 92			log.Println(err)
 93		}
 94	}
 95
 96	destination := query.Get("url")
 97	name := query.Get("name")
 98	oldName := query.Get("oldName")
 99
100	var message string
101
102	if action == "create" {
103		if len(destination) == 0 {
104			message = "URL field is required"
105			http.Redirect(writer, request, "/?message="+message, 302)
106			return
107		}
108
109		if len(name) == 0 {
110			name = uniuri.NewLen(4)
111			for m.nameExists(name) {
112				name = uniuri.NewLen(4)
113				log.Println("Generated new name:", name)
114			}
115		} else if m.nameExists(name) {
116			http.Error(writer, "406 Not Acceptable: A shortened URL with this name already exists", 406)
117			message = "A shortened URL with this name already exists"
118			http.Redirect(writer, request, "/?message="+message, 302)
119			return
120		}
121
122		message = url.QueryEscape(m.create(name, destination))
123		http.Redirect(writer, request, "/?message="+message, 302)
124		return
125	}
126
127	if action == "edit" {
128		_, err = io.WriteString(writer, m.edit(name, destination))
129		if err != nil {
130			log.Println(err)
131		}
132	}
133
134	if action == "update" {
135		if len(destination) == 0 {
136			message = "URL field is required"
137			http.Redirect(writer, request, "/?message="+message, 302)
138			return
139		}
140
141		if len(name) == 0 {
142			message = "Name field is required"
143			http.Redirect(writer, request, "/?message="+message, 302)
144			return
145		}
146
147		if len(oldName) == 0 {
148			message = "oldName field is required"
149			http.Redirect(writer, request, "/?message="+message, 302)
150			return
151		}
152
153		if len(name) != 0 && oldName != name {
154			if m.nameExists(name) {
155				message = "A shortened URL with this name already exists"
156				http.Redirect(writer, request, "/?message="+message, 302)
157				return
158			}
159		}
160
161		message := url.QueryEscape(m.update(name, destination, oldName))
162		http.Redirect(writer, request, "/?message="+message, 302)
163	}
164
165	if action == "delete" {
166		if len(name) == 0 {
167			message = "Name field is required"
168			http.Redirect(writer, request, "/?message="+message, 302)
169		}
170		message := url.QueryEscape(m.delete(name))
171		log.Println(message)
172		http.Redirect(writer, request, "/?message="+message, 302)
173	}
174}