Skip to content

Commit

Permalink
Add a package to abstract SQL operations
Browse files Browse the repository at this point in the history
The data package should improve code-reuse by bundling together the SQL
operations into a common package. It will be marginally less efficient
than using SQL directly, but it will enforce best practices, remove
duplication and prevent mistakes from broken queries. #7 is the
associated issue.

To begin with, this updates termine to use the new package. It also
refactors termine a bit.

Fixes #3
  • Loading branch information
Merovius committed Jul 30, 2016
1 parent f5c9136 commit 1a3d667
Show file tree
Hide file tree
Showing 11 changed files with 615 additions and 221 deletions.
422 changes: 422 additions & 0 deletions data/data.go

Large diffs are not rendered by default.

90 changes: 27 additions & 63 deletions termine/announce.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"bytes"
"database/sql"
"errors"
"flag"
"fmt"
"io"
Expand All @@ -12,7 +13,8 @@ import (
"os"
"os/exec"
"text/template"
"time"

"github.com/nnev/website/data"
)

var cmdAnnounce = &Command{
Expand All @@ -31,18 +33,7 @@ func init() {
cmdAnnounce.Run = RunAnnounce
}

func isStammtisch(date time.Time) (stammt bool, err error) {
err = db.QueryRow("SELECT stammtisch FROM termine WHERE date = $1", date).Scan(&stammt)
return
}

func announceStammtisch(date time.Time) {
loc, err := getLocation(date)
if err != nil {
log.Println("Kann Location nicht auslesen:", err)
return
}

func announceStammtisch(t *data.Termin) error {
maildraft := `Liebe Treffler,
am kommenden Donnerstag ist wieder Stammtisch. Diesmal sind wir bei {{.Location}}.
Expand All @@ -56,43 +47,22 @@ Damit wir passend reservieren können, tragt bitte bis Dienstag Abend,

mailtmpl := template.Must(template.New("maildraft").Parse(maildraft))
mailbuf := new(bytes.Buffer)
type data struct {
Location string
}
if err = mailtmpl.Execute(mailbuf, data{loc}); err != nil {
log.Println("Fehler beim Füllen des Templates:", err)
return
if err := mailtmpl.Execute(mailbuf, t); err != nil {
return fmt.Errorf("Fehler beim Füllen des Templates: %v", err)
}
mail := mailbuf.Bytes()

sendAnnouncement("Bitte für Stammtisch eintragen", mail)
return sendAnnouncement("Bitte für Stammtisch eintragen", mail)
}

func announceC14(date time.Time) {
var data struct {
Topic,
Abstract,
Speaker string
}

if err := db.QueryRow("SELECT topic FROM vortraege WHERE date = $1", date).Scan(&data.Topic); err != nil {
if err == sql.ErrNoRows {
fmt.Println("Es gibt nächsten Donnerstag noch keine c¼h. :(")
return
}

log.Println("Kann topic nicht auslesen:", err)
return
}

if err := db.QueryRow("SELECT abstract FROM vortraege WHERE date = $1", date).Scan(&data.Abstract); err != nil {
log.Println("Kann abstract nicht auslesen:", err)
return
func announceC14(t *data.Termin) error {
v, err := t.GetVortrag(cmdAnnounce.Tx)
if err == sql.ErrNoRows {
fmt.Println("Es gibt nächsten Donnerstag noch keine c¼h. :(")
return nil
}

if err := db.QueryRow("SELECT speaker FROM vortraege WHERE date = $1", date).Scan(&data.Speaker); err != nil {
log.Println("Kann speaker nicht auslesen:", err)
return
if err != nil {
log.Fatal("Kann vortrag nicht lesen:", err)
}

maildraft := `Liebe Treffler,
Expand All @@ -113,15 +83,14 @@ Wer mehr Informationen möchte:

mailtmpl := template.Must(template.New("maildraft").Parse(maildraft))
mailbuf := new(bytes.Buffer)
if err := mailtmpl.Execute(mailbuf, data); err != nil {
log.Println("Fehler beim Füllen des Templates:", err)
return
if err := mailtmpl.Execute(mailbuf, v); err != nil {
return fmt.Errorf("Fehler beim Füllen des Templates: %v", err)
}
mail := mailbuf.Bytes()
sendAnnouncement(data.Topic, mail)
return sendAnnouncement(v.Topic, mail)
}

func sendAnnouncement(subject string, msg []byte) {
func sendAnnouncement(subject string, msg []byte) error {
mail := new(bytes.Buffer)
fmt.Fprintf(mail, "From: [email protected]\r\n")
fmt.Fprintf(mail, "To: %s\r\n", mime.QEncoding.Encode("utf-8", *targetmailaddr))
Expand All @@ -147,25 +116,20 @@ func sendAnnouncement(subject string, msg []byte) {
log.Println("Output von Sendmail:")
io.Copy(os.Stderr, stdout)
}
return nil
}

func RunAnnounce() {
var nextRelevantDate time.Time

if err := db.QueryRow("SELECT date FROM termine WHERE date > NOW() AND override = '' ORDER BY date ASC LIMIT 1").Scan(&nextRelevantDate); err != nil {
log.Println("Kann nächsten Termin nicht auslesen:", err)
return
func RunAnnounce() error {
t, err := data.FutureTermine(cmdAnnounce.Tx).First()
if err == sql.ErrNoRows {
return errors.New("Keine termine gefunden")
}

isStm, err := isStammtisch(nextRelevantDate)
if err != nil {
log.Println("Kann stammtischiness nicht auslesen:", err)
return
return fmt.Errorf("Kann nächsten Termin nicht auslesen: %v", err)
}

if isStm {
announceStammtisch(nextRelevantDate)
} else {
announceC14(nextRelevantDate)
if t.Stammtisch.Bool {
return announceStammtisch(t)
}
return announceC14(t)
}
9 changes: 5 additions & 4 deletions termine/clear.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package main

import (
"flag"
"log"
"fmt"
)

var cmdClear = &Command{
Expand All @@ -21,9 +21,10 @@ func init() {
cmdClear.Run = RunClear
}

func RunClear() {
_, err := db.Exec("DELETE FROM zusagen")
func RunClear() error {
_, err := cmdClear.Tx.Exec("DELETE FROM zusagen")
if err != nil {
log.Println("Kann Tabelle nicht leeren:", err)
return fmt.Errorf("Kann Tabelle nicht leeren: %v", err)
}
return nil
}
12 changes: 4 additions & 8 deletions termine/help.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,22 +50,18 @@ func showGlobalHelp() {
flag.PrintDefaults()
}

func RunHelp() {
func RunHelp() error {
if cmdHelp.Flag.NArg() < 1 {
showGlobalHelp()
return
return nil
}

for _, cmd := range Commands {
if cmd.Name() == "help" {
continue
}

if cmd.Name() == cmdHelp.Flag.Arg(0) {
showCmdHelp(cmd)
return
return nil
}
}

log.Printf("Unbekannter Befehl \"%s\"\n", cmdHelp.Flag.Arg(0))
return fmt.Errorf("Unbekannter Befehl \"%s\"\n", cmdHelp.Flag.Arg(0))
}
63 changes: 21 additions & 42 deletions termine/location.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package main

import (
"database/sql"
"errors"
"flag"
"fmt"
"log"
"os"
"time"

"github.com/nnev/website/data"
)

var cmdLocation = &Command{
Expand All @@ -24,51 +28,26 @@ func init() {
cmdLocation.Run = RunLocation
}

func getLocation(date time.Time) (location string, err error) {
err = db.QueryRow("SELECT location FROM termine WHERE date = $1", date).Scan(&location)
return
}
func RunLocation() error {
if cmdLocation.Flag.NArg() > 1 {
showCmdHelp(cmdLocation)
os.Exit(1)
}

func setLocation(date time.Time, location string) (updated bool, err error) {
result, err := db.Exec("UPDATE termine SET location = $2 WHERE date = $1", date, location)
if err != nil {
return false, err
t, err := data.QueryTermine(cmdLocation.Tx, "WHERE date >= $1 AND stammtisch = true", time.Now()).First()
if err == sql.ErrNoRows {
return errors.New("Termin muss erst mittels next hinzugefügt werden.")
}
n, err := result.RowsAffected()
if err != nil {
return false, err
}

return n > 0, nil
}

func RunLocation() {
// Wir holen uns die nächsten 5 Donnerstage -- darunter muss ein Stammtisch
// sein
var stammtisch time.Time
for _, d := range getNextThursdays(5) {
if d.Day() < 8 {
stammtisch = d
break
}
return fmt.Errorf("Kann Termin nicht lesen: %v", err)
}

if cmdLocation.Flag.NArg() == 0 {
loc, err := getLocation(stammtisch)
if err != nil {
log.Println("Kann Location nicht auslesen:", err)
return
}
fmt.Println(loc)
} else {
updated, err := setLocation(stammtisch, cmdLocation.Flag.Arg(0))
if err != nil {
log.Println("Kann Location nicht setzen:", err)
return
}
if !updated {
log.Println("Termin noch nicht vorhanden.")
log.Println("Füge ihn erst mittels next hinzu.")
}
fmt.Println(t.Location)
return nil
}
t.Location = cmdLocation.Flag.Arg(1)
if err = t.Update(cmdLocation.Tx); err != nil {
return fmt.Errorf("Kann Location nicht setzen: %v", err)
}
return nil
}
Loading

0 comments on commit 1a3d667

Please sign in to comment.