1package main
  2
  3import (
  4	"fmt"
  5	"io"
  6	"log"
  7	"net/http"
  8	"net/url"
  9	"strings"
 10
 11	"github.com/dchest/uniuri"
 12	"github.com/dgraph-io/badger/v3"
 13)
 14
 15func (m model) root(writer http.ResponseWriter, request *http.Request) {
 16	path := request.URL.Path
 17	if path != "/" {
 18		destinationKey := strings.TrimPrefix(path, "/")
 19		err := m.database.View(func(txn *badger.Txn) error {
 20			destinationEntry, err := txn.Get([]byte(destinationKey))
 21			if err == nil {
 22				destinationValue, err := destinationEntry.ValueCopy(nil)
 23				if err != nil {
 24					return err
 25				}
 26				log.Println("Redirecting visitor to \"" + string(destinationValue) + "\"")
 27				http.Redirect(writer, request, string(destinationValue), 302)
 28			}
 29			return err
 30		})
 31		if err != nil {
 32			io.WriteString(writer, string(err.Error()))
 33		}
 34		return
 35	}
 36
 37	cookie, err := request.Cookie("access_token")
 38	if err != nil || cookie.Value != m.AccessToken {
 39		io.WriteString(writer, unauthenticated())
 40		return
 41	}
 42
 43	query := request.URL.Query()
 44
 45	action := query.Get("action")
 46	if len(action) == 0 {
 47		io.WriteString(writer, m.authenticated())
 48	}
 49
 50	destination := query.Get("url")
 51	name := query.Get("name")
 52	oldName := query.Get("oldName")
 53
 54	var message string
 55
 56	if action == "create" {
 57		if len(destination) == 0 {
 58			message = "URL field is required"
 59			http.Redirect(writer, request, "/?message="+message, 302)
 60			return
 61		}
 62
 63		if len(name) == 0 {
 64			name = uniuri.NewLen(4)
 65			for m.nameExists(name) {
 66				name = uniuri.NewLen(4)
 67				log.Println("Generated new name:", name)
 68			}
 69		} else if m.nameExists(name) {
 70			http.Error(writer, "406 Not Acceptable: A shortened URL with this name already exists", 406)
 71			message = "A shortened URL with this name already exists"
 72			http.Redirect(writer, request, "/?message="+message, 302)
 73			return
 74		}
 75
 76		message = url.QueryEscape(m.create(name, destination))
 77		http.Redirect(writer, request, "/?message="+message, 302)
 78		return
 79	}
 80
 81	if action == "edit" {
 82		io.WriteString(writer, m.edit(name, destination))
 83	}
 84
 85	if action == "update" {
 86		if len(destination) == 0 {
 87			message = "URL field is required"
 88			http.Redirect(writer, request, "/?message="+message, 302)
 89			return
 90		}
 91
 92		if len(name) == 0 {
 93			message = "Name field is required"
 94			http.Redirect(writer, request, "/?message="+message, 302)
 95			return
 96		}
 97
 98		if len(oldName) == 0 {
 99			message = "oldName field is required"
100			http.Redirect(writer, request, "/?message="+message, 302)
101			return
102		}
103
104		if len(name) != 0 && oldName != name {
105			if m.nameExists(name) {
106				message = "A shortened URL with this name already exists"
107				http.Redirect(writer, request, "/?message="+message, 302)
108				return
109			}
110		}
111
112		message := url.QueryEscape(m.update(name, destination, oldName))
113		http.Redirect(writer, request, "/?message="+message, 302)
114	}
115
116	if action == "delete" {
117		if len(name) == 0 {
118			message = "Name field is required"
119			http.Redirect(writer, request, "/?message="+message, 302)
120		}
121		message := url.QueryEscape(m.delete(name))
122		log.Println(message)
123		http.Redirect(writer, request, "/?message="+message, 302)
124	}
125}
126
127func (m model) genTable() string {
128	var table string
129	err := m.database.View(func(txn *badger.Txn) error {
130		opts := badger.DefaultIteratorOptions
131		opts.PrefetchSize = 10
132		iterator := txn.NewIterator(opts)
133		defer iterator.Close()
134		for iterator.Rewind(); iterator.Valid(); iterator.Next() {
135			item := iterator.Item()
136			k := item.Key()
137			err := item.Value(func(v []byte) error {
138				table = table + fmt.Sprintf(`<tr>
139	<td><p>%s</p></td>
140	<td><p>%s</p></td>
141	<td><a href="/?action=edit&name=%s&url=%s">Edit</a><a href="/?action=delete&name=%s">Delete</a></td>
142</tr>`, k, v, k, url.QueryEscape(string(v)), k)
143				return nil
144			})
145			if err != nil {
146				return err
147			}
148		}
149		return nil
150	})
151	if err != nil {
152		return err.Error()
153	}
154	return table
155}