First commit

This commit is contained in:
2022-06-29 21:26:05 -04:00
commit e7559f0bf1
48 changed files with 8132 additions and 0 deletions

96
backend/utils/datatype.go Normal file
View File

@@ -0,0 +1,96 @@
package utils
import (
"database/sql"
"database/sql/driver"
"encoding/json"
"strings"
"time"
)
type Date time.Time // 2006-01-02
type DateTime time.Time // 2006-01-02 15:04:05
func (date *Date) UnmarshalJSON(b []byte) error {
s := strings.Trim(string(b), "\"")
t, err := time.Parse("2006-01-02", s)
if err != nil {
return err
}
*date = Date(t)
return nil
}
func (date Date) MarshalJSON() ([]byte, error) {
return json.Marshal(time.Time(date))
}
func (date Date) Format(s string) string {
t := time.Time(date)
return t.Format(s)
}
func (date *Date) Scan(value interface{}) (err error) {
nullTime := &sql.NullTime{}
err = nullTime.Scan(value)
*date = Date(nullTime.Time)
return
}
func (date Date) Value() (driver.Value, error) {
return time.Time(date), nil
}
func (date Date) GormDataType() string {
return "date"
}
func (date Date) GobEncode() ([]byte, error) {
return time.Time(date).GobEncode()
}
func (date *Date) GobDecode(b []byte) error {
return (*time.Time)(date).GobDecode(b)
}
func (dateTime *DateTime) UnmarshalJSON(b []byte) error {
s := strings.Trim(string(b), "\"")
t, err := time.Parse("2006-01-02 15:04:05", s)
if err != nil {
return err
}
*dateTime = DateTime(t)
return nil
}
func (dateTime DateTime) MarshalJSON() ([]byte, error) {
return json.Marshal(time.Time(dateTime))
}
func (dateTime DateTime) Format(s string) string {
t := time.Time(dateTime)
return t.Format(s)
}
func (date *DateTime) Scan(value interface{}) (err error) {
nullTime := &sql.NullTime{}
err = nullTime.Scan(value)
*date = DateTime(nullTime.Time)
return
}
func (date DateTime) Value() (driver.Value, error) {
return time.Time(date), nil
}
func (date DateTime) GormDataType() string {
return "datetime"
}
func (date DateTime) GobEncode() ([]byte, error) {
return time.Time(date).GobEncode()
}
func (date *DateTime) GobDecode(b []byte) error {
return (*time.Time)(date).GobDecode(b)
}

View File

@@ -0,0 +1,191 @@
package utils
import (
"reflect"
"testing"
"time"
)
func TestDateUnmarshalJSON(t *testing.T) {
want := "1985-02-23 00:00:00 +0000 UTC"
var date Date
err := date.UnmarshalJSON([]byte("\"1985-02-23\""))
msg := time.Time(date).String()
if msg != want {
t.Fatalf(`date.UnmarshalJSON([]byte("\"1985-02-23\"") = %q, %v, want match for %#q, nil`, msg, err, want)
}
}
func TestDateUnmarshalJSONMalformed(t *testing.T) {
want := error(&time.ParseError{})
var date Date
err := date.UnmarshalJSON([]byte("\"1985/02/23\""))
msg := time.Time(date).String()
if reflect.TypeOf(err) != reflect.TypeOf(want) {
t.Fatalf(`date.UnmarshalJSON([]byte("\"1985/02/23\"") = %q, %v, want match for %#q, nil`, msg, err, want)
}
}
func TestDateMarshalJSON(t *testing.T) {
want := "\"1985-02-23T00:00:00Z\""
parsed, _ := time.Parse("2006-01-02", "1985-02-23")
var date Date = Date(parsed)
msg, err := date.MarshalJSON()
if string(msg) != want {
t.Fatalf(`date.MarshalJSON() = %q, %v, want match for %#q, nil`, msg, err, want)
}
}
func TestDateFormat(t *testing.T) {
want := "Feb 23, 1985"
parsed, _ := time.Parse("2006-01-02", "1985-02-23")
var date Date = Date(parsed)
msg := date.Format("Jan 2, 2006")
if msg != want {
t.Fatalf(`date.Format("Jan 2, 2006") = %q, want match for %#q, nil`, msg, want)
}
}
func TestDateScan(t *testing.T) {
want := "0001-01-01T00:00:00Z"
parsed, _ := time.Parse("2006-01-02", "1985-02-23")
var date Date = Date(parsed)
err := date.Scan(Date{})
msg := date.Format("2006-01-02T15:04:05Z07:00")
if msg != want {
t.Fatalf(`date.Scan(Date{}) = %q, %v, want match for %#q, nil`, msg, err, want)
}
}
func TestDateValue(t *testing.T) {
var want time.Time
parsed, _ := time.Parse("2006-01-02", "1985-02-23")
var date Date = Date(parsed)
msg, _ := date.Value()
if reflect.TypeOf(msg) != reflect.TypeOf(want) {
t.Fatalf(`date.Value() = %q, want match for %#q, nil`, msg, want)
}
}
func TestDateGormDateType(t *testing.T) {
want := "date"
parsed, _ := time.Parse("2006-01-02", "1985-02-23")
var date Date = Date(parsed)
msg := date.GormDataType()
if msg != want {
t.Fatalf(`date.GormDateType() = %q, want match for %#q, nil`, msg, want)
}
}
func TestDateGobEncode(t *testing.T) {
want := "\x01\x00\x00\x00\x0e\x94\x0f!\x00\x00\x00\x00\x00\xff\xff"
parsed, _ := time.Parse("2006-01-02", "1985-02-23")
var date Date = Date(parsed)
msg, err := date.GobEncode()
if string(msg) != want {
t.Fatalf(`date.GobEncode() = %q, %v, want match for %#q, nil`, msg, err, want)
}
}
func TestDateGobDecode(t *testing.T) {
want := "1985-02-23T00:00:00Z"
parsed, _ := time.Parse("2006-01-02", "2006-01-02")
var date Date = Date(parsed)
err := date.GobDecode([]byte("\x01\x00\x00\x00\x0e\x94\x0f!\x00\x00\x00\x00\x00\xff\xff"))
msg := date.Format("2006-01-02T15:04:05Z07:00")
if string(msg) != want {
t.Fatalf(`date.GobDecode([]byte()) = %q, %v, want match for %#q, nil`, msg, err, want)
}
}
func TestDateTimeUnmarshalJSON(t *testing.T) {
want := "1985-02-23 12:13:14 +0000 UTC"
var dateTime DateTime
err := dateTime.UnmarshalJSON([]byte("\"1985-02-23 12:13:14\""))
msg := time.Time(dateTime).String()
if msg != want {
t.Fatalf(`dateTime.UnmarshalJSON([]byte("\"1985-02-23 12:13:14\"") = %q, %v, want match for %#q, nil`, msg, err, want)
}
}
func TestDateTimeUnmarshalJSONMalformed(t *testing.T) {
want := error(&time.ParseError{})
var dateTime DateTime
err := dateTime.UnmarshalJSON([]byte("\"1985/02/23 12-13-14\""))
msg := time.Time(dateTime).String()
if reflect.TypeOf(err) != reflect.TypeOf(want) {
t.Fatalf(`dateTime.UnmarshalJSON([]byte("\"1985/02/23 12-13-14\"") = %q, %v, want match for %#q, nil`, msg, err, want)
}
}
func TestDateTimeMarshalJSON(t *testing.T) {
want := "\"1985-02-23T12:13:14Z\""
parsed, _ := time.Parse("2006-01-02 15:04:05", "1985-02-23 12:13:14")
var dateTime DateTime = DateTime(parsed)
msg, err := dateTime.MarshalJSON()
if string(msg) != want {
t.Fatalf(`dateTime.MarshalJSON() = %q, %v, want match for %#q, nil`, msg, err, want)
}
}
func TestDateTimeFormat(t *testing.T) {
want := "Feb 23, 1985 12:13:14"
parsed, _ := time.Parse("2006-01-02 15:04:05", "1985-02-23 12:13:14")
var dateTime DateTime = DateTime(parsed)
msg := dateTime.Format("Jan 2, 2006 15:04:05")
if msg != want {
t.Fatalf(`dateTime.Format("Jan 2, 2006 15:04:05") = %q, want match for %#q, nil`, msg, want)
}
}
func TestDateTimeScan(t *testing.T) {
want := "0001-01-01T00:00:00Z"
parsed, _ := time.Parse("2006-01-02 15:04:05", "1985-02-23 12:13:14")
var dateTime DateTime = DateTime(parsed)
err := dateTime.Scan(Date{})
msg := dateTime.Format("2006-01-02T15:04:05Z07:00")
if msg != want {
t.Fatalf(`dateTime.Scan(Date{}) = %q, %v, want match for %#q, nil`, msg, err, want)
}
}
func TestDateTimeValue(t *testing.T) {
var want time.Time
parsed, _ := time.Parse("2006-01-02 15:04:05", "1985-02-23 12:13:14")
var dateTime DateTime = DateTime(parsed)
msg, _ := dateTime.Value()
if reflect.TypeOf(msg) != reflect.TypeOf(want) {
t.Fatalf(`dateTime.Value() = %q, want match for %#q, nil`, msg, want)
}
}
func TestDateTimeGormDateType(t *testing.T) {
want := "datetime"
parsed, _ := time.Parse("2006-01-02 15:04:05", "1985-02-23 12:13:14")
var dateTime DateTime = DateTime(parsed)
msg := dateTime.GormDataType()
if msg != want {
t.Fatalf(`dateTime.GormDateType() = %q, want match for %#q, nil`, msg, want)
}
}
func TestDateTimeGobEncode(t *testing.T) {
want := "\x01\x00\x00\x00\x0e\x94\x0f\xcc\xda\x00\x00\x00\x00\xff\xff"
parsed, _ := time.Parse("2006-01-02 15:04:05", "1985-02-23 12:13:14")
var dateTime DateTime = DateTime(parsed)
msg, err := dateTime.GobEncode()
if string(msg) != want {
t.Fatalf(`dateTime.GobEncode() = %q, %v, want match for %#q, nil`, msg, err, want)
}
}
func TestDateTimeGobDecode(t *testing.T) {
want := "1985-02-23T12:13:14Z"
parsed, _ := time.Parse("2006-01-02 15:04:05", "2006-01-02 12:13:14")
var dateTime DateTime = DateTime(parsed)
err := dateTime.GobDecode([]byte("\x01\x00\x00\x00\x0e\x94\x0f\xcc\xda\x00\x00\x00\x00\xff\xff"))
msg := dateTime.Format("2006-01-02T15:04:05Z07:00")
if string(msg) != want {
t.Fatalf(`dateTime.GobDecode([]byte()) = %q, %v, want match for %#q, nil`, msg, err, want)
}
}

16
backend/utils/json.go Normal file
View File

@@ -0,0 +1,16 @@
package utils
import (
"encoding/json"
"net/http"
)
type ErrorMessage struct {
ErrorMessage string `json:"error_message"`
}
func JSONErrorOutput(writer http.ResponseWriter, status int, msg string) {
writer.Header().Set("Content-Type", "application/json")
writer.WriteHeader(status)
json.NewEncoder(writer).Encode(ErrorMessage{ErrorMessage: msg})
}

52
backend/utils/jwt.go Normal file
View File

@@ -0,0 +1,52 @@
package utils
import (
"errors"
"os"
"time"
"github.com/golang-jwt/jwt/v4"
)
type JWTClaim struct {
Username string `json:"username"`
Email string `json:"email"`
jwt.RegisteredClaims
}
func GenerateJWT(email string, username string) (tokenString string, err error) {
expirationTime := time.Now().Add(1 * time.Hour)
claims := &JWTClaim{
Email: email,
Username: username,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(expirationTime),
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, err = token.SignedString(os.Getenv("JWT_SECRET"))
return
}
func ValidateToken(signedToken string) (err error) {
token, err := jwt.ParseWithClaims(
signedToken,
&JWTClaim{},
func(token *jwt.Token) (interface{}, error) {
return []byte(os.Getenv("JWT_SECRET")), nil
},
)
if err != nil {
return
}
claims, ok := token.Claims.(*JWTClaim)
if !ok {
err = errors.New("couldn't parse claims")
return
}
if claims.ExpiresAt.Unix() < jwt.NewNumericDate(time.Now().Local()).Unix() {
err = errors.New("token expired")
return
}
return
}

115
backend/utils/rut.go Normal file
View File

@@ -0,0 +1,115 @@
package utils
import (
"errors"
"strconv"
"strings"
)
type RutType int8
const (
Run RutType = iota
Rut
)
func (r RutType) String() string {
switch r {
case Run:
return "RUN"
case Rut:
return "RUT"
default:
return "unknown"
}
}
func CleanRut(rut *string) {
*rut = strings.ToUpper(*rut)
*rut = strings.TrimSpace(*rut)
*rut = strings.Replace(*rut, ".", "", -1)
*rut = strings.Replace(*rut, "-", "", -1)
}
func PrettyRut(rut *string) {
tempRut := *rut
verifier := strings.ToUpper(tempRut[len(tempRut)-1:])
tempRut = tempRut[:len(tempRut)-1]
tempRut = Reverse(tempRut)
tempRut = InsertNth(tempRut, 3, '.')
tempRut = Reverse(tempRut)
tempRut = tempRut + "-" + verifier
*rut = tempRut
}
func IsValidRut(rut string) (bool, error) {
// rut should be 8 or 9 characters
if len(rut) != 8 && len(rut) != 9 {
return false, errors.New("incorrect RUT length")
}
verifier := strings.ToUpper(rut[len(rut)-1:])
tempRut := rut[:len(rut)-1]
_, err := strconv.Atoi(verifier)
if err != nil && verifier != "K" {
return false, errors.New("invalid RUT identifier")
}
generatedVerifier, err := generateVerifier(tempRut)
if err != nil {
return false, err
}
if verifier != generatedVerifier {
return false, errors.New("incorrect RUT verifier")
}
return true, nil
}
func GetRutType(rut string) (RutType, error) {
tempRut := rut[:len(rut)-1]
numericRut, err := strconv.Atoi(tempRut)
if err != nil {
return Run, errors.New("invalid RUN/RUT")
}
if numericRut < 100000000 && numericRut > 50000000 {
return Rut, nil
} else {
return Run, nil
}
}
func generateVerifier(rut string) (string, error) {
if _, err := strconv.Atoi(rut); err != nil {
return "", errors.New("invalid RUT")
}
var multiplier = 2
var sum = 0
var remainder int
var division int
var rutLength = len(rut)
for i := rutLength - 1; i >= 0; i-- {
sum = sum + toInt(rut[i:i+1])*multiplier
multiplier++
if multiplier == 8 {
multiplier = 2
}
}
division = sum / 11
division = division * 11.0
remainder = sum - int(division)
if remainder != 0 {
remainder = 11 - remainder
}
if remainder == 10 {
return "K", nil
} else {
return strconv.Itoa(remainder), nil
}
}

138
backend/utils/rut_test.go Normal file
View File

@@ -0,0 +1,138 @@
package utils
import (
"testing"
)
func TestRutTypeRun(t *testing.T) {
typeTest := Run
want := "RUN"
msg := typeTest.String()
if msg != want {
t.Fatalf(`typeTest.String() = %q, want match for %#q, nil`, msg, want)
}
}
func TestRutTypeRut(t *testing.T) {
typeTest := Rut
want := "RUT"
msg := typeTest.String()
if msg != want {
t.Fatalf(`typeTest.String() = %q, want match for %#q, nil`, msg, want)
}
}
func TestRutTypeUnknown(t *testing.T) {
var typeTest RutType = 2
want := "unknown"
msg := typeTest.String()
if msg != want {
t.Fatalf(`typeTest.String() = %q, want match for %#q, nil`, msg, want)
}
}
func TestCleanRut(t *testing.T) {
want := "8675309K"
msg := "8.675.309-k"
CleanRut(&msg)
if msg != want {
t.Fatalf(`CleanRut(&msg) = %q, want match for %#q, nil`, msg, want)
}
}
func TestPrettyRut(t *testing.T) {
want := "8.675.309-K"
msg := "8675309k"
PrettyRut(&msg)
if msg != want {
t.Fatalf(`PrettyRut(&msg) = %q, want match for %#q, nil`, msg, want)
}
}
func TestGenerateVerifier(t *testing.T) {
want := "K"
msg, err := generateVerifier("8675309")
if msg != want {
t.Fatalf(`generateVerifier("8675309") = %q, %v, want match for %#q, nil`, msg, err, want)
}
}
func TestGenerateVerifier2(t *testing.T) {
want := "9"
msg, err := generateVerifier("86753095")
if msg != want {
t.Fatalf(`generateVerifier("86753095") = %q, %v, want match for %q, nil`, msg, err, want)
}
}
func TestGenerateVerifierInvalidString(t *testing.T) {
want := "invalid RUT"
_, err := generateVerifier("8675f309")
if err.Error() != want {
t.Fatalf(`generateVerifier("8675f309") = %q, want %q, nil`, err.Error(), want)
}
}
func TestIsValidRut(t *testing.T) {
want := true
msg, err := IsValidRut("8675309K")
if msg != want {
t.Fatalf(`IsValidRut("8675309K") = false, %v, want match for true, nil`, err)
}
}
func TestIsValidRutInvalid(t *testing.T) {
want := false
msg, err := IsValidRut("86753T99")
if msg != want {
t.Fatalf(`IsValidRut("86753T99") = true, %v, want match for false, nil`, err)
}
}
func TestIsValidRutInvalidIdentifier(t *testing.T) {
want := false
msg, err := IsValidRut("8675309C")
if msg != want {
t.Fatalf(`IsValidRut("8675309C") = true, %v, want match for false, nil`, err)
}
}
func TestIsValidRutIncorrectLength(t *testing.T) {
want := false
msg, err := IsValidRut("123234")
if msg != want {
t.Fatalf(`IsValidRut("123234") = true, %v, want match for false, nil`, err)
}
}
func TestIsValidRutIncorrectIdentifier(t *testing.T) {
want := false
msg, err := IsValidRut("86753096")
if msg != want {
t.Fatalf(`IsValidRut("86753096") = true, %v, want match for false, nil`, err)
}
}
func TestGetRutTypeRun(t *testing.T) {
want := Run
msg, err := GetRutType("8675309K")
if msg != want {
t.Fatalf(`GetRutType("8675309") = %q, %v, want match for %#q, nil`, msg, err, want)
}
}
func TestGetRutTypeRut(t *testing.T) {
want := Rut
msg, err := GetRutType("867530959")
if msg != want {
t.Fatalf(`GetRutType("867530959") = %q, %v, want match for %#q, nil`, msg, err, want)
}
}
func TestGetRutTypeRutInvalid(t *testing.T) {
want := "invalid RUN/RUT"
_, err := GetRutType("8675f309")
if err.Error() != want {
t.Fatalf(`GetRutType("8675f309") = %q, want %q, nil`, err.Error(), want)
}
}

32
backend/utils/utils.go Normal file
View File

@@ -0,0 +1,32 @@
package utils
import (
"bytes"
"strconv"
)
func toInt(toConvert string) int {
converted, _ := strconv.Atoi(toConvert)
return converted
}
func Reverse(s string) string {
r := []rune(s)
for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
r[i], r[j] = r[j], r[i]
}
return string(r)
}
func InsertNth(s string, n int, symbol rune) string {
var buffer bytes.Buffer
var n_1 = n - 1
var l_1 = len(s) - 1
for i, rune := range s {
buffer.WriteRune(rune)
if i%n == n_1 && i != l_1 {
buffer.WriteRune(symbol)
}
}
return buffer.String()
}

View File

@@ -0,0 +1,37 @@
package utils
import (
"testing"
)
func TestReverse(t *testing.T) {
want := "8675309"
msg := Reverse("9035768")
if msg != want {
t.Fatalf(`Reverse("9035768") = %q, want match for %#q, nil`, msg, want)
}
}
func TestInsertNth(t *testing.T) {
want := "867.530.9"
msg := InsertNth("8675309", 3, '.')
if msg != want {
t.Fatalf(`InsertNth("8675309") = %q, want match for %#q, nil`, msg, want)
}
}
func TestToInt(t *testing.T) {
want := 123
msg := toInt("123")
if msg != want {
t.Fatalf(`toInt("123") = %q, want match for %#q, nil`, msg, want)
}
}
func TestToIntInvalid(t *testing.T) {
want := 123
msg := toInt("12f3")
if msg == want {
t.Fatalf(`toInt("12f3") = %q, want match for %#q, nil`, msg, want)
}
}