Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a package to abstract SQL operations #18

Merged
merged 9 commits into from
Jul 30, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
427 changes: 427 additions & 0 deletions data/data.go

Large diffs are not rendered by default.

93 changes: 28 additions & 65 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 {
Copy link
Member

@cherti cherti Jul 30, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

t *date.Termin: one character-variables are easy to write, but having an actual word is better for later when someone works into the code.

Therefore imho s/t/termin/ here (and in the places where it is used).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cf. variable name style and named result parameters (even though this is about a parameter, but the same reasoning applies). In short: a) variable/parameter name lengths should be inversely correlated to the distance between declaration and use and b) the signature of a function should be readable and not stutter (termin *data.Termin would be an example of stuttering).

Your personal opinion on this particular styleguide item might differ (mine doesn't), but in any case I'd prefer to go with the clear mandate of the go culture here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same applies to the other instances of this comment.

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 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here with t.

vortrag, 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, vortrag); err != nil {
return fmt.Errorf("Fehler beim Füllen des Templates: %v", err)
}
mail := mailbuf.Bytes()
sendAnnouncement(data.Topic, mail)
return sendAnnouncement(vortrag.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 @@ -143,29 +112,23 @@ func sendAnnouncement(subject string, msg []byte) {
cmd.Stderr = stdout

if err := cmd.Run(); err != nil {
log.Println("Fehler beim Senden der Mail: ", err)
log.Println("Output von Sendmail:")
io.Copy(os.Stderr, stdout)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we are handing errors upwards anyways, it would be consequenial to return some error here as well, wouldn't it? Can be implemented later though, but we should file an issue then, so that it is done eventually.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I'm considering it in-scope and have added it.

return fmt.Errorf("Fehler beim Senden der Mail: %v", err)
}
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()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/t/nextTermin/

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
}
31 changes: 17 additions & 14 deletions termine/help.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,21 @@ func init() {
}

func showCmdHelp(cmd *Command) {
log.Println("Nutzung:\n")
log.Println(" ", cmd.UsageLine, "\n")
log.Println("Nutzung:")
log.Println()
log.Println(" ", cmd.UsageLine)
log.Println()
log.Println(cmd.Long)
}

func showGlobalHelp() {
log.Println("Tool zum Bearbeiten der nnev-Termin Datenbank\n")
log.Println("Nutzung:\n")
log.Println("Tool zum Bearbeiten der nnev-Termin Datenbank.")
log.Println()
log.Println("Nutzung:")
log.Println()
log.Printf(" %s [flags] befehl [argumente]\n\n", os.Args[0])
log.Println("Die vorhandenen Befehle sind:\n")
log.Println("Die vorhandenen Befehle sind:")
log.Println()

w := tabwriter.NewWriter(os.Stderr, 8, 4, 2, ' ', 0)

Expand All @@ -45,27 +50,25 @@ func showGlobalHelp() {

log.Printf("\nDie Benutzung eines Befehls zeigt dir \"%s help [befehl]\" an.\n", os.Args[0])

log.Println("\nFlags:\n")
log.Println()
log.Println("Flags:")
log.Println()

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