helperfuncs.go

  1// SPDX-FileCopyrightText: 2022 Amolith <amolith@secluded.site>
  2//
  3// SPDX-License-Identifier: BSD-2-Clause
  4
  5package main
  6
  7import (
  8	"errors"
  9	"fmt"
 10	"log"
 11	"strings"
 12	"text/template"
 13
 14	"github.com/dgraph-io/badger/v3"
 15)
 16
 17// Create shortens a given URL with an optional name. If a name is provided,
 18// that name will be used. Otherwise, 4-character string will be generated and
 19// used instead.
 20func (m model) create(name string, url string) string {
 21	err := m.database.Update(func(txn *badger.Txn) error {
 22		return txn.Set([]byte(name), []byte(url))
 23	})
 24	if err != nil {
 25		return fmt.Sprint(err)
 26	}
 27
 28	log.Println("\"" + url + "\" mapped to \"" + name + "\"")
 29	return fmt.Sprint("URL mapped to ", name, "\n")
 30}
 31
 32// read() accepts a start variable for the first link in a set (implying reverse
 33// iteration), an end variable for the last link in a set (implying forward
 34// iteration), and a count variable for the number of requested entries. The
 35// requested set is returned as JSON.
 36func (m model) read(start string, end string, count int) (map[string]string, error) {
 37	links := make(map[string]string)
 38
 39	if !(count > 0) {
 40		return nil, errors.New("Count parameter is required")
 41	}
 42
 43	err := m.database.View(func(txn *badger.Txn) error {
 44		opts := badger.DefaultIteratorOptions
 45		opts.PrefetchSize = 10
 46		if start != "" && end == "" {
 47			opts.Reverse = true
 48		}
 49		iterator := txn.NewIterator(opts)
 50		if start != "" && end == "" {
 51			iterator.Seek([]byte(end))
 52		} else if start == "" && end != "" {
 53			iterator.Seek([]byte(start))
 54		}
 55		defer iterator.Close()
 56		for iterator.Rewind(); iterator.Valid(); iterator.Next() {
 57			err := iterator.Item().Value(func(v []byte) error {
 58				links[string(iterator.Item().Key())] = string(v)
 59				return nil
 60			})
 61			if err != nil {
 62				return err
 63			}
 64		}
 65		return nil
 66	})
 67	if err != nil {
 68		return nil, err
 69	}
 70
 71	return links, nil
 72}
 73
 74// Update modifies a shortened link
 75func (m model) update(name string, url string, oldName string) string {
 76	m.create(name, url)
 77	if name != oldName {
 78		m.delete(oldName)
 79	}
 80	return fmt.Sprint("\"" + url + "\" mapped to \"" + name + "\"")
 81}
 82
 83// Delete removes a shortened URL from the database given its name.
 84func (m model) delete(name string) string {
 85	err := m.database.Update(func(txn *badger.Txn) error {
 86		return txn.Delete([]byte(name))
 87	})
 88	if err != nil {
 89		return fmt.Sprint(err)
 90	}
 91
 92	log.Println("\"" + name + "\" has been deleted")
 93	return fmt.Sprint("\"" + name + "\" has been deleted\n")
 94}
 95
 96// nameExists returns true if the provided name is already stored in the
 97// database and false if it's not.
 98func (m model) nameExists(name string) bool {
 99	err := m.database.View(func(txn *badger.Txn) error {
100		_, err := txn.Get([]byte(name))
101		if err != nil {
102			return err
103		}
104		return nil
105	})
106	return err == nil
107}
108
109// unauthenticated serves the unauthenticated home page to the visitor
110func unauthenticated() string {
111	home, err := templates.ReadFile("templates/home_unauthenticated.html")
112	if err != nil {
113		log.Fatalln(err)
114	}
115	return string(home)
116}
117
118// authenticated serves the authenticated dashboard to the user
119func (m model) authenticated() string {
120	dash, err := templates.ReadFile("templates/home_authenticated.html")
121	if err != nil {
122		log.Fatalln(err)
123	}
124	tmpl, err := template.New("authenticated").Parse(string(dash))
125	if err != nil {
126		log.Println(err)
127	}
128	page := new(strings.Builder)
129	err = tmpl.Execute(page, m.genTable())
130	if err != nil {
131		log.Println(err)
132	}
133	return page.String()
134}
135
136type EditFields struct {
137	URL  string
138	Name string
139}
140
141// update serves the editing interface to the user
142func (m model) edit(name string, url string) string {
143	fields := EditFields{url, name}
144	editPage, err := templates.ReadFile("templates/edit.html")
145	if err != nil {
146		log.Fatalln(err)
147	}
148	tmpl, err := template.New("editPage").Parse(string(editPage))
149	if err != nil {
150		log.Println(err)
151	}
152	page := new(strings.Builder)
153	err = tmpl.Execute(page, fields)
154	if err != nil {
155		log.Println(err)
156	}
157	return page.String()
158}