Skip to content

Commit

Permalink
push my working tree
Browse files Browse the repository at this point in the history
doesn't work/build, contains things other than mx, I just want to get this off my laptop
  • Loading branch information
lillian committed Feb 2, 2024
1 parent 9209141 commit 794585a
Show file tree
Hide file tree
Showing 34 changed files with 1,455 additions and 9 deletions.
4 changes: 4 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@ RUN apk add go
WORKDIR /build
COPY . .
RUN go build -o hl-web ./cmd/web
RUN go build -o hl-mx ./cmd/mx
RUN go build -o hl-worker ./cmd/worker
# RUN go build -o hl-apply ./cmd/apply
# RUN go build -o hl-memberizer ./cmd/memberizer

FROM alpine:latest
COPY --from=builder /build/hl-web /usr/local/bin/hl-web
COPY --from=builder /build/hl-mx /usr/local/bin/hl-mx
COPY --from=builder /build/hl-worker /usr/local/bin/hl-worker
68 changes: 68 additions & 0 deletions cmd/helcimapi/helcimapi.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
module.exports.findCustomer = async ({name, email}) => {
console.log("looking for customer", name, email)

let res = await fetch("https://api.helcim.com/v2/customers/", {
headers: { "api-token": process.env.NEW_TOKEN }
});

let customers = await res.json();
// console.log(customers);

let customerByEmail = !!email ? customers.find(c => c.billingAddress?.email === email || c.shippingAddress?.email === email) : null;
let customerByName = !!name ? customers.find(c => c.contactName === name || c.billingAddress?.name === name || c.shippingAddress?.name === name) : null;

if (!customerByEmail && !customerByName) {
console.log("could not find customer!");
return null;
}

if (!customerByEmail) return customerByName;
if (!customerByName) return customerByEmail;

if (customerByEmail.customerCode != customerByName.customerCode) {
throw { userVisibleError: "Matched different customers by name and email!" };
}

return customerByEmail;
}

const { XMLParser } = require("fast-xml-parser");

module.exports.findSubscription = async (customerID) => {
console.log("querying subscriptions for customer " + customerID);

let res = await fetch("https://secure.myhelcim.com/api/recurring/subscription-search", {
method: "POST",
body: `customerCode=${customerID}`,
headers: {
"account-id": process.env.ACCOUNT_ID,
"api-token": "thisdoesntmatter",
"content-type": "application/x-www-form-urlencoded",
}
});

let xml = await res.text();

const parsert = new XMLParser();
let unxmled = parsert.parse(xml)?.subscriptions?.subscription;

console.log(unxmled);

console.log(typeof unxmled)

if (Array.isArray(unxmled)) {
return unxmled.find(s => s.recurringPlanCode === "member1st" && s.status === "Active");
}

if (typeof unxmled === 'object') {
if (unxmled.recurringPlanCode === "member1st" && unxmled.status === "Active") {
return unxmled;
}
return null;
}

if (!unxmled) return null;

console.log(unxmled);
throw 'unknown unxmled type';
}
63 changes: 63 additions & 0 deletions cmd/helcimapi/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
require("dotenv").config();

const http = require("http");

const { findCustomer, findSubscription } = require("./helcimapi.js");

const getBody = (r) => new Promise(res => {
let data = '';
r.on('data', (chunk) => data += chunk);
r.on('end', () => res(data));
})

const process = async (data) => {
if (!data.name && !data.email) {
throw { userVisibleError: "must have either 'name' or 'email' in request" };
}

let customer = await findCustomer(data);
if (!customer) return [200, { ok: false }]; //throw { userVisibleError: "Customer record not found" };
console.log("found customer", customer);

let subscription = await findSubscription(customer.customerCode);
console.log("found subscription?", subscription);
return [200, { ok: !!subscription }]
}

const handler = async (req, res) => {
console.log(req.method, req.url, req.headers);
let data = await getBody(req);

if (!data) return;
try {
data = JSON.parse(data);
} catch (e) {
console.error(e);
res.statusCode = 400;
res.end();
return;
}

console.log("d", data);

let status, body;

try {
[status, body] = await process(data);
} catch(e) {
if (e?.userVisibleError) {
status = 400;
body = { error: e.userVisibleError };
} else {
console.error(e);
status = 500;
body = {"error": "500 internal server error"}
}
}

res.statusCode = status;
res.write(JSON.stringify(body));
res.end();
};

http.createServer(handler).listen(8080, "0.0.0.0")
7 changes: 7 additions & 0 deletions cmd/helcimapi/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"dependencies": {
"dotenv": "^16.3.1",
"fast-xml-parser": "^4.3.2"
}
}

3 changes: 3 additions & 0 deletions cmd/import-mail/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package main

// maybe listadm package idk
23 changes: 23 additions & 0 deletions cmd/mx/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package main

import (
"fmt"
"log"
"members-platform/internal/db"

"github.com/emersion/go-smtp"
)

func main() {
if err := db.ConnectRedis(); err != nil {
log.Fatalln(fmt.Errorf("connect redis: %w", err))
}

s := smtp.NewServer(&recvBackend{})

s.Addr = "100.80.182.53:2525"
s.Domain = "lists.hacklab.to"

log.Println("Starting SMTP server at", s.Addr)
log.Fatal(s.ListenAndServe())
}
62 changes: 62 additions & 0 deletions cmd/mx/recv.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package main

import (
"bytes"
"fmt"
"io"

"github.com/emersion/go-message"
"github.com/emersion/go-smtp"

jobs "members-platform/internal/jobs"
)

type recvBackend struct{}

func (recvBackend) NewSession(c *smtp.Conn) (smtp.Session, error) {
return &session{rcpt: []string{}}, nil
}

type session struct {
mailfrom string
rcpt []string
}

// todo: clear session
func (s *session) Reset() {}

func (s *session) AuthPlain(username, password string) error {
return smtp.ErrAuthUnsupported
}

func (s *session) Mail(from string, opts *smtp.MailOptions) error {
s.mailfrom = from
return nil
}

func (s *session) Rcpt(to string, opts *smtp.RcptOptions) error {
s.rcpt = append(s.rcpt, to)
return nil
}

func (s *session) Data(r io.Reader) error {
data, err := io.ReadAll(r)
if err != nil {
return fmt.Errorf("failed to read email data: %w", err)
}

_, err = message.Read(bytes.NewReader(data))
if err != nil {
return fmt.Errorf("parse message: %w", err)
}

return jobs.EnqueueJob(jobs.JOB_MX_INBOUND, jobs.MxInboundJobData{
MailFrom: s.mailfrom,
Rcpt: s.rcpt,
Data: data,
})
}

func (s *session) Logout() error {
return smtp.ErrAuthUnsupported
}
4 changes: 4 additions & 0 deletions cmd/web/ui/pageStructs.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@ type Confirmation struct {
Title string
Message template.HTML
}

type ApplyData struct {
Error string
}
68 changes: 67 additions & 1 deletion cmd/web/ui/pages/apply.html
Original file line number Diff line number Diff line change
@@ -1,2 +1,68 @@
{{ if IsLoggedOut .Ctx.AuthLevel }}
<form class="w-full max-w-sm" hx-post="/apply/" method="post">
<h2 class="text-xl">Membership Application</h2>
<br>
<input type="hidden" name="type" value="login" />
Enter the password to apply:
<div class="md:flex md:items-center mb-6">
<div class="md:w-2/3">
<input class="bg-gray-200 appearance-none border-2 border-gray-200 rounded w-full py-2 px-4 text-gray-700 leading-tight focus:outline-none focus:bg-white" id="inline-password" type="password" name="password">
</div>
</div>
<button class="shadow bg-blue-500 hover:bg-blue-400 focus:shadow-outline focus:outline-none text-white font-bold py-2 px-4 rounded" type="submit">
Log in
</button>
{{ if .Data }}
{{ if .Data.Error }}
<p class="text-red-500">Error: {{ .Data.Error }}</p>
{{ end }}
{{ end }}
</form>
{{ else if IsMemberLoggedIn .Ctx.AuthLevel }}
<h2 class="text-xl">Membership Application</h2>
<br>
<p>You are already a member!</p>
{{ else }}
<!-- todo: ask for APPLY_PASSWORD env variable, add to session -->
<p>TODO: put form here</p>
<form>
<h2 class="text-xl">Membership Application</h2>
<div class="columns-2xs">
<label class="block text-gray-500 font-bold md:text-right mb-1 md:mb-0 pr-4" for="inline-full-name">
Preferred Full Name
</label>
<input class="bg-gray-200 appearance-none border-2 border-gray-200 rounded w-full py-2 px-4 text-gray-700 leading-tight focus:outline-none focus:bg-white" id="inline-full-name" type="text" name="username">
<label class="block text-gray-500 font-bold md:text-right mb-1 md:mb-0 pr-4" for="inline-full-name">
Username
</label>
<input class="bg-gray-200 appearance-none border-2 border-gray-200 rounded w-full py-2 px-4 text-gray-700 leading-tight focus:outline-none focus:bg-white" id="inline-full-name" type="text" name="username">
<label class="block text-gray-500 font-bold md:text-right mb-1 md:mb-0 pr-4" for="inline-full-name">
Nickname
</label>
<input class="bg-gray-200 appearance-none border-2 border-gray-200 rounded w-full py-2 px-4 text-gray-700 leading-tight focus:outline-none focus:bg-white" id="inline-full-name" type="text" name="username">
<label class="block text-gray-500 font-bold md:text-right mb-1 md:mb-0 pr-4" for="inline-full-name">
Contact Email address
</label>
<input class="bg-gray-200 appearance-none border-2 border-gray-200 rounded w-full py-2 px-4 text-gray-700 leading-tight focus:outline-none focus:bg-white" id="inline-full-name" type="text" name="username">
<label class="block text-gray-500 font-bold md:text-right mb-1 md:mb-0 pr-4" for="inline-full-name">
Mailing List Email address
</label>
<input class="bg-gray-200 appearance-none border-2 border-gray-200 rounded w-full py-2 px-4 text-gray-700 leading-tight focus:outline-none focus:bg-white" id="inline-full-name" type="text" name="username">
</div>
<br>
<label class="block text-gray-500 font-bold md:text-right mb-1 md:mb-0 pr-4" for="inline-full-name">
Why do you want to join Hacklab?
</label>
<input class="bg-gray-200 appearance-none border-2 border-gray-200 rounded w-full py-2 px-4 text-gray-700 leading-tight focus:outline-none focus:bg-white" id="inline-full-name" type="text" name="username">
<br>
<div class="columns-2xs">
<label class="block text-gray-500 font-bold md:text-right mb-1 md:mb-0 pr-4" for="inline-full-name">
Name of first sponsoring member
</label>
<input class="bg-gray-200 appearance-none border-2 border-gray-200 rounded w-full py-2 px-4 text-gray-700 leading-tight focus:outline-none focus:bg-white" id="inline-full-name" type="text" name="username">
<label class="block text-gray-500 font-bold md:text-right mb-1 md:mb-0 pr-4" for="inline-full-name">
Name of second sponsoring member
</label>
<input class="bg-gray-200 appearance-none border-2 border-gray-200 rounded w-full py-2 px-4 text-gray-700 leading-tight focus:outline-none focus:bg-white" id="inline-full-name" type="text" name="username">
</div>
</form>
{{ end }}
18 changes: 18 additions & 0 deletions cmd/web/ui/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,24 @@ func Router() chi.Router {
}
})

r.Post("/apply/", func(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
log.Println(err)
}

// todo: parse form to here
// https://godocs.io/github.com/go-playground/form
// todo: validate
// https://godocs.io/github.com/go-playground/validator/v10
// errReply := ApplyData{}

// switch r.Form.Get("type") {
// case "login":
// password := r.Form.Get("password")
// correctPassword := ""
// }
})

return r
}

Expand Down
Loading

0 comments on commit 794585a

Please sign in to comment.