Skip to content
Commits on Source (4)
......@@ -5,6 +5,7 @@ import (
"crypto/sha256"
"encoding/hex"
"fmt"
"os"
"regexp"
)
......@@ -22,69 +23,92 @@ func (app *App) Run(listing Listing) error {
// Send emails
for _, user := range listing {
userCount := 0
err := app.Service.DB.QueryRowContext(app.Context, `SELECT COUNT(1) FROM users WHERE uuid=$1`, user.Uuid).Scan(&userCount)
if err != nil {
return fmt.Errorf("Error checking previous presence of user %s: %s", user.Uuid, err.Error())
}
if userCount == 1 {
// User is present, and has received an email already, skip
continue
}
if userCount != 0 {
return fmt.Errorf("Unique uuid violation for %s", user.Uuid)
}
userPrivateTokenRaw := make([]byte, 32)
n, err := rand.Read(userPrivateTokenRaw)
if err != nil {
return fmt.Errorf("Error making private token: %s", err)
}
if n != 32 {
return fmt.Errorf("Error making private token: %d != 32", n)
}
userPrivateToken := hex.EncodeToString(userPrivateTokenRaw)
userPublicTokenRaw := sha256.Sum256([]byte(userPrivateToken))
userPublicToken := hex.EncodeToString(userPublicTokenRaw[:])
tx, err := app.Service.DB.Begin()
if err != nil {
return fmt.Errorf("Transaction error: %s", user.Uuid, err.Error())
}
_, err = tx.ExecContext(app.Context, `
err := func() error {
tx, err := app.Service.DB.Begin()
if err != nil {
return fmt.Errorf("Transaction error: %s", user.Uuid, err.Error())
}
userCount := 0
err = tx.QueryRowContext(app.Context, `SELECT COUNT(1) FROM users WHERE uuid=$1`, user.Uuid).Scan(&userCount)
if err != nil {
return fmt.Errorf("Error checking previous presence of user %s: %s", user.Uuid, err.Error())
}
if userCount == 1 {
// User is present, and has received an email already, skip
return fmt.Errorf("User already present")
}
if userCount != 0 {
return fmt.Errorf("Unique uuid violation for %s", user.Uuid)
}
userPrivateTokenRaw := make([]byte, 32)
n, err := rand.Read(userPrivateTokenRaw)
if err != nil {
return fmt.Errorf("Error making private token: %s", err)
}
if n != 32 {
return fmt.Errorf("Error making private token: %d != 32", n)
}
userPrivateToken := hex.EncodeToString(userPrivateTokenRaw)
userPublicTokenRaw := sha256.Sum256([]byte(userPrivateToken))
userPublicToken := hex.EncodeToString(userPublicTokenRaw[:])
_, err = tx.ExecContext(app.Context, `
INSERT INTO users(uuid, public_token, fullname, email, admin)
VALUES($1, $2, $3, $4, $5)
`, user.Uuid, userPublicToken, user.Fullname, user.Email, user.Admin)
if err != nil {
tx.Rollback()
return fmt.Errorf("Error inserting user: %s", err)
}
if err != nil {
tx.Rollback()
return fmt.Errorf("Error inserting user: %s", err)
}
body := fmt.Sprintf(EMAIL_TOKEN_BODY, user.Fullname, userPrivateToken)
err = app.Service.Email.Send(user.Email, EMAIL_TOKEN_SUBJECT, body)
if err != nil {
return fmt.Errorf("Error sending email: %s", err)
}
body := fmt.Sprintf(EMAIL_TOKEN_BODY, user.Fullname, userPrivateToken)
fmt.Println(body)
// app.Service.Email.Send(user.Email, EMAIL_TOKEN_SUBJECT)
err = tx.Commit()
if err != nil {
return fmt.Errorf("Error committing transation: %s", err)
}
return nil
}()
err = tx.Commit()
if err != nil {
return fmt.Errorf("Error committing transation: %s", err)
fmt.Fprintf(os.Stderr, "Email error for %s (%s): %s\n", user.Fullname, user.Uuid, err.Error())
} else {
fmt.Fprintf(os.Stdout, "Email sent for %s (%s)\n", user.Fullname, user.Uuid)
}
}
return nil
}
// TODO listing des votants pour les admins
const EMAIL_TOKEN_SUBJECT = "AG Électrolab - Votre accès au vote en ligne"
const EMAIL_TOKEN_SUBJECT = "AG Electrolab - Votre acces au vote en ligne"
const EMAIL_TOKEN_BODY = `Bonjour %s,
En raison du confinement, l'assemblée générale de l'Électrolab a lieu sur internet. Vous pourrez suivre la présentation à cette addresse: httosL.
Vous recevez ce mail car vous êtes membre actif de l'association Electrolab. De par les statuts de l'association, vous disposez du droit de vote à l'assemblée générale qui aura lieu le 19/06/2021 à 15h.
L'assemblée générale ayant lieu cette année à distance du fait des risques sanitaires liés à l'épidémie de Covid 19, le vote se fera par voie électronique.
Vous pourrez suivre la présentation à cette adresse: https://www.youtube.com/user/ElectrolabFr
Si vous vous inscrivez à la chaîne et que vous cliquez sur la cloche, vous serez prévenu au moment du lancement du live.
Sinon, rendez-vous à partir de 14h45, le live s’affichera dès l’accueil de notre chaîne en haut de la liste des vidéos.
Pour intervenir ou poser des questions, il faudra soit écrire dans le chat de la page Youtube en lien ci-dessus, soit écrire dans le chat de l'association : https://chat.electrolab.fr/electrolab/channels/ag2021 (si par exemple vous n’avez pas de compte youtube ou si vous préférez passer par ce canal). Des modérateurs seront présents pour lire les messages sur ces deux canaux et transmettre les questions aux intervenants.
Le présent courrier électronique contient un code unique qui vous permettra de voter sur les différents points de cette assemblée générale. Ce code unique est personnel et ne permet de voter qu'une seule fois.
La procuration du vote se fait en transmettant le code unique à la personne à qui on cède son pouvoir.
Pour voter, rendez-vous à l'adresse suivante :
https://vote.electrolab.fr/events/Electrolab-AG-2021/votes?private_token=%s
Vous pourrez voter sur les différents points de l'assemblée générale en vous rendant à l'adresse suivante:
Si vous avez des questions, n'hésitez pas à nous écrire à contact@electrolab.fr, ou sur le chat de l'association https://chat.electrolab.fr
https://vote.electrolab.fr/Electrolab-AG-2020/votes?private_token=%s
Librement,
Le CA
`
......@@ -22,7 +22,7 @@ var (
)
func RegisterRoutes(mux *http.ServeMux, app *server.App) {
mux.Handle("/events/Electrolab-AG-2020/votes/", server.NewAppHandler(app, handlePage))
mux.Handle("/events/Electrolab-AG-2021/votes/", server.NewAppHandler(app, handlePage))
}
func handlePage(app *server.App, ctx context.Context, w http.ResponseWriter, r *http.Request) {
......
......@@ -42,7 +42,7 @@ const TEMPLATE_STR = `
<div class="vote-page">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item" aria-current="page"><a href="../votes?private_token={{.User.PrivateToken}}">AG Électrolab 2020</a></li>
<li class="breadcrumb-item" aria-current="page"><a href="../votes?private_token={{.User.PrivateToken}}">AG Électrolab 2021</a></li>
<li class="breadcrumb-item active" aria-current="page">
<a href="?private_token={{.User.PrivateToken}}">
Vote nº{{.Question.Position}} - {{.Question.Title}}
......
......@@ -15,7 +15,7 @@ var (
)
func RegisterRoutes(mux *http.ServeMux, app *server.App) {
mux.Handle("/events/Electrolab-AG-2020/votes", server.NewAppHandler(app, handleGetVotes))
mux.Handle("/events/Electrolab-AG-2021/votes", server.NewAppHandler(app, handleGetVotes))
}
func handleGetVotes(app *server.App, ctx context.Context, w http.ResponseWriter, r *http.Request) {
......
......@@ -13,7 +13,7 @@ type TemplateIndexVars struct {
const TEMPLATE_STR = `
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item active" aria-current="page"><a href="?private_token={{.User.PrivateToken}}">AG Électrolab 2020</a></li>
<li class="breadcrumb-item active" aria-current="page"><a href="?private_token={{.User.PrivateToken}}">AG Électrolab 2021</a></li>
</ol>
</nav>
......
......@@ -7,18 +7,23 @@ import (
)
func main() {
if len(os.Args) != 2 {
return fmt.Printf("Usage: %s <import_listing.json>", os.Args[0])
os.Exit(1)
}
if err := Run(); err != nil {
fmt.Fprintf(os.Stderr, "Fatal error: %s\n", err.Error())
}
}
func Run() error {
config, err := importer.ReadConfigFile("importer.json")
config, err := importer.ReadConfigFile("config/config-importer.json")
if err != nil {
return err
}
listing, err := importer.ReadListingFile("listing.json")
listing, err := importer.ReadListingFile(os.Args[1])
if err != nil {
return err
}
......
......@@ -33,7 +33,7 @@ func Run() error {
mux := http.NewServeMux()
pages.RegisterRoutes(mux, app)
fmt.Println("http://localhost:8081/events/Electrolab-AG-2020/votes?private_token=7717e6ba488ff754fea8b57b22048c6dc6115f2c37b9fc8e87321da76045cbfb")
fmt.Println("http://localhost:8081/events/Electrolab-AG-2021/votes?private_token=7717e6ba488ff754fea8b57b22048c6dc6115f2c37b9fc8e87321da76045cbfb")
http.ListenAndServe(":8081", mux)
return nil
......
......@@ -4,5 +4,5 @@
. _dev.secret
function psql() {
/Applications/Postgres.app/Contents/Versions/12/bin/psql --variable ON_ERROR_STOP=1 --no-psqlrc "$@"
/Applications/Postgres.app/Contents/Versions/latest/bin/psql --variable ON_ERROR_STOP=1 --no-psqlrc "$@"
}
......@@ -12,6 +12,7 @@ DATABASE_NAME="votes"
DATABASE_USER="postgres"
DATABASE_FILE="database.sql"
psql --quiet --command "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE pid <> pg_backend_pid() AND datname = '$DATABASE_NAME'"
psql --quiet --command "DROP DATABASE IF EXISTS $DATABASE_NAME"
psql --quiet --command "CREATE DATABASE $DATABASE_NAME WITH OWNER = $DATABASE_USER"
......
......@@ -44,7 +44,7 @@ func (s *Smtp) Name() string {
}
func (s *Smtp) Send(to string, subject, body string) error {
msg := fmt.Sprintf("From: %s\nTo: %s\nSubject: %s\n\n%s\n", s.fromEmail, to, subject, body)
msg := fmt.Sprintf("From: %s\nTo: %s\nSubject: %s\nContent-Type:text/plain; charset=UTF-8\n\n%s\n", s.fromEmail, to, subject, body)
msg = strings.Replace(msg, "\n", "\r\n", -1)
if !s.disabled {
serverAddr := fmt.Sprintf("%s:%d", s.address, s.port)
......