Deno re-write
This commit is contained in:
101
lib/email.go
101
lib/email.go
@ -1,101 +0,0 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net/smtp"
|
||||
"os"
|
||||
)
|
||||
|
||||
func SendEmail(to_email string, from_email string, from_name string, html string, subject string) {
|
||||
LogInfo.Println("Starting email sending process")
|
||||
|
||||
// Set up authentication information.
|
||||
auth := smtp.PlainAuth(
|
||||
"",
|
||||
os.Getenv("SMTP_USERNAME"),
|
||||
os.Getenv("SMTP_PASSWORD"),
|
||||
os.Getenv("SMTP_HOST"),
|
||||
)
|
||||
|
||||
LogSuccess.Println("Authentication set up")
|
||||
|
||||
// Connect to the server, authenticate, set the sender and recipient,
|
||||
// and send the email all in one step.
|
||||
msg := []byte("From: " + from_name + " <" + from_email + ">\r\n" +
|
||||
"To: " + to_email + "\r\n" +
|
||||
"Subject: " + subject + "\r\n" +
|
||||
"Content-Type: text/html; charset=UTF-8" + "\r\n" +
|
||||
"\r\n" +
|
||||
html + "\r\n")
|
||||
|
||||
tlsconfig := &tls.Config{
|
||||
InsecureSkipVerify: false,
|
||||
ServerName: os.Getenv("SMTP_HOST"),
|
||||
}
|
||||
|
||||
LogSuccess.Println("TLS configuration set up")
|
||||
|
||||
c, err := smtp.Dial(os.Getenv("SMTP_HOST") + ":587")
|
||||
if err != nil {
|
||||
LogError.Println("Error dialing SMTP server:", err)
|
||||
return
|
||||
}
|
||||
|
||||
LogSuccess.Println("Connected to SMTP server")
|
||||
|
||||
if err = c.StartTLS(tlsconfig); err != nil {
|
||||
LogError.Println("Error starting TLS:", err)
|
||||
return
|
||||
}
|
||||
|
||||
LogInfo.Println("TLS started")
|
||||
|
||||
if err = c.Auth(auth); err != nil {
|
||||
LogError.Println("Error authenticating with SMTP server:", err)
|
||||
return
|
||||
}
|
||||
|
||||
LogSuccess.Println("Authenticated with SMTP server")
|
||||
|
||||
if err = c.Mail(from_email); err != nil {
|
||||
LogError.Println("Error setting sender address:", err)
|
||||
return
|
||||
}
|
||||
|
||||
LogSuccess.Println("Sender address set")
|
||||
|
||||
if err = c.Rcpt(to_email); err != nil {
|
||||
LogError.Println("Error setting recipient address:", err)
|
||||
return
|
||||
}
|
||||
|
||||
LogSuccess.Println("Recipient address set")
|
||||
|
||||
w, err := c.Data()
|
||||
if err != nil {
|
||||
LogError.Println("Error getting write closer:", err)
|
||||
return
|
||||
}
|
||||
|
||||
LogSuccess.Println("Got write closer")
|
||||
|
||||
_, err = w.Write(msg)
|
||||
if err != nil {
|
||||
LogError.Println("Error writing message:", err)
|
||||
return
|
||||
}
|
||||
|
||||
LogSuccess.Println("Message written")
|
||||
|
||||
err = w.Close()
|
||||
if err != nil {
|
||||
LogError.Println("Error closing write closer:", err)
|
||||
return
|
||||
}
|
||||
|
||||
LogSuccess.Println("Write closer closed")
|
||||
|
||||
c.Quit()
|
||||
|
||||
LogSuccess.Println("Email sent successfully")
|
||||
}
|
33
lib/files.go
33
lib/files.go
@ -1,33 +0,0 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// ListFiles returns a slice of file paths in the given directory
|
||||
func ListFiles(dir string) ([]string, error) {
|
||||
var filePaths []string
|
||||
|
||||
entries, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
if entry.IsDir() {
|
||||
// Recursively list files in subdirectories
|
||||
subDir := filepath.Join(dir, entry.Name())
|
||||
subFiles, err := ListFiles(subDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
filePaths = append(filePaths, subFiles...)
|
||||
} else {
|
||||
// Add file path to the slice
|
||||
filePath := filepath.Join(dir, entry.Name())
|
||||
filePaths = append(filePaths, filePath)
|
||||
}
|
||||
}
|
||||
return filePaths, nil
|
||||
}
|
33
lib/img.go
33
lib/img.go
@ -1,33 +0,0 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/png"
|
||||
"mime/multipart"
|
||||
|
||||
"golang.org/x/image/draw"
|
||||
)
|
||||
|
||||
func ResizeImg(file multipart.File, width int, height int) ([]byte, error) {
|
||||
// Read and decode image
|
||||
img, _, err := image.Decode(file)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decode error: %w", err)
|
||||
}
|
||||
|
||||
// Create new RGBA image
|
||||
dst := image.NewRGBA(image.Rect(0, 0, width, height))
|
||||
|
||||
// Resize using high-quality interpolation
|
||||
draw.CatmullRom.Scale(dst, dst.Bounds(), img, img.Bounds(), draw.Over, nil)
|
||||
|
||||
// Encode to PNG
|
||||
buf := new(bytes.Buffer)
|
||||
if err := png.Encode(buf, dst); err != nil {
|
||||
return nil, fmt.Errorf("encode error: %w", err)
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
26
lib/links.go
26
lib/links.go
@ -1,26 +0,0 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
)
|
||||
|
||||
type IconLink struct {
|
||||
Name string
|
||||
Href string
|
||||
Icon template.HTML
|
||||
}
|
||||
|
||||
type CardLink struct {
|
||||
Name string
|
||||
Href string
|
||||
Description string
|
||||
Date string
|
||||
Tags []string
|
||||
Internal bool
|
||||
}
|
||||
|
||||
type ButtonLink struct {
|
||||
Name string
|
||||
Href string
|
||||
Internal bool
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"github.com/gookit/color"
|
||||
)
|
||||
|
||||
// Error logging
|
||||
var LogError = color.Style{
|
||||
color.FgRed,
|
||||
color.OpBold,
|
||||
}
|
||||
|
||||
// Info logging
|
||||
var LogInfo = color.Style{
|
||||
color.FgCyan,
|
||||
color.OpBold,
|
||||
}
|
||||
|
||||
// Success logging
|
||||
var LogSuccess = color.Style{
|
||||
color.FgGreen,
|
||||
color.OpBold,
|
||||
}
|
||||
|
||||
// Warning logging
|
||||
var LogWarning = color.Style{
|
||||
color.FgYellow,
|
||||
color.OpBold,
|
||||
}
|
||||
|
||||
// Debug logging
|
||||
var LogDebug = color.Style{
|
||||
color.FgMagenta,
|
||||
color.OpBold,
|
||||
}
|
||||
|
||||
// Custom logging
|
||||
var LogCustom = color.Style{
|
||||
color.FgWhite,
|
||||
color.OpBold,
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"strings"
|
||||
|
||||
"github.com/yuin/goldmark"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
type FrontMatter struct {
|
||||
Name string
|
||||
Description string
|
||||
Date string
|
||||
Tags []string
|
||||
}
|
||||
|
||||
func ExtractFrontMatter(file fs.DirEntry, contentFS fs.FS) (CardLink, error) {
|
||||
f, err := contentFS.Open(file.Name())
|
||||
if err != nil {
|
||||
return CardLink{}, fmt.Errorf("failed to open file: %w", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
scanner := bufio.NewScanner(f)
|
||||
var lines []string
|
||||
for scanner.Scan() {
|
||||
lines = append(lines, scanner.Text())
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
return CardLink{}, fmt.Errorf("failed to read file: %w", err)
|
||||
}
|
||||
|
||||
content := strings.Join(lines, "\n")
|
||||
splitContent := strings.SplitN(content, "---", 3)
|
||||
if len(splitContent) < 3 {
|
||||
return CardLink{}, fmt.Errorf("invalid file format: %s", file.Name())
|
||||
}
|
||||
|
||||
frontMatter := CardLink{}
|
||||
if err := yaml.Unmarshal([]byte(splitContent[1]), &frontMatter); err != nil {
|
||||
return CardLink{}, fmt.Errorf("failed to unmarshal frontmatter: %w", err)
|
||||
}
|
||||
|
||||
md := goldmark.New(goldmark.WithExtensions())
|
||||
var buf bytes.Buffer
|
||||
if err := md.Convert([]byte(splitContent[2]), &buf); err != nil {
|
||||
return CardLink{}, fmt.Errorf("failed to convert markdown: %w", err)
|
||||
}
|
||||
|
||||
return frontMatter, nil
|
||||
}
|
||||
|
||||
func SplitFrontmatter(md []byte) (frontmatter []byte, content []byte, err error) {
|
||||
parts := bytes.SplitN(md, []byte("---"), 3)
|
||||
|
||||
if len(parts) < 3 {
|
||||
return nil, nil, errors.New("invalid or missing frontmatter")
|
||||
}
|
||||
|
||||
return parts[1], parts[2], nil
|
||||
}
|
66
lib/sse.go
66
lib/sse.go
@ -1,66 +0,0 @@
|
||||
package lib
|
||||
|
||||
import "sync"
|
||||
|
||||
type SSEServerType struct {
|
||||
clients map[string]map[chan string]bool
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
var SSEServer *SSEServerType
|
||||
|
||||
func init() {
|
||||
SSEServer = &SSEServerType{
|
||||
clients: make(map[string]map[chan string]bool),
|
||||
}
|
||||
}
|
||||
|
||||
func NewSSEServer() *SSEServerType {
|
||||
return &SSEServerType{
|
||||
clients: make(map[string]map[chan string]bool),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SSEServerType) AddClient(channel string, client chan string) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
if _, ok := s.clients[channel]; !ok {
|
||||
s.clients[channel] = make(map[chan string]bool)
|
||||
}
|
||||
s.clients[channel][client] = true
|
||||
|
||||
LogInfo.Printf("\nClient connected to channel %s\n", channel)
|
||||
}
|
||||
|
||||
func (s *SSEServerType) RemoveClient(channel string, client chan string) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
delete(s.clients[channel], client)
|
||||
if len(s.clients[channel]) == 0 {
|
||||
delete(s.clients, channel)
|
||||
}
|
||||
|
||||
LogInfo.Printf("\nClient disconnected from channel %s\n", channel)
|
||||
}
|
||||
|
||||
func (s *SSEServerType) ClientCount(channel string) int {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
return len(s.clients[channel])
|
||||
}
|
||||
|
||||
func (s *SSEServerType) SendSSE(channel string, message string) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
go func() {
|
||||
for client := range s.clients[channel] {
|
||||
client <- message
|
||||
}
|
||||
}()
|
||||
|
||||
LogDebug.Printf("\nMessage broadcast on channel %s: %s\n", channel, message)
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
templatefs "atri.dad/pages/templates"
|
||||
)
|
||||
|
||||
func RenderTemplate(w http.ResponseWriter, layout string, partials []string, props interface{}) error {
|
||||
// Get the name of the current file
|
||||
_, filename, _, _ := runtime.Caller(1)
|
||||
page := filepath.Base(filename)
|
||||
page = page[:len(page)-len(filepath.Ext(page))] // remove the file extension
|
||||
|
||||
// Build the list of templates
|
||||
templates := []string{
|
||||
"layouts/" + layout + ".html",
|
||||
page + ".html",
|
||||
}
|
||||
for _, partial := range partials {
|
||||
templates = append(templates, "partials/"+partial+".html")
|
||||
}
|
||||
|
||||
// Parse the templates
|
||||
ts, err := template.ParseFS(templatefs.FS, templates...)
|
||||
if err != nil {
|
||||
LogError.Print(err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
// Execute the layout template
|
||||
err = ts.ExecuteTemplate(w, layout, props)
|
||||
if err != nil {
|
||||
LogError.Print(err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
Reference in New Issue
Block a user