Skip to content

Commit

Permalink
added charm logger and fixed the .env reader
Browse files Browse the repository at this point in the history
  • Loading branch information
danielgrbacbravo committed Dec 4, 2023
1 parent ec5a12a commit 0de4020
Show file tree
Hide file tree
Showing 9 changed files with 95 additions and 119 deletions.
5 changes: 0 additions & 5 deletions auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,14 @@ func GetCsrfToken(doc *goquery.Document) (string, error) {
// If the login fails, an error is returned along with the corresponding status code.
func Login(client http.Client, route string, loginData url.Values) (http.Client, error) {
resp, err := client.PostForm(route, loginData)

if err != nil {
fmt.Println("Error logging in:", err)
return client, err
}
defer resp.Body.Close()

// Check if login was successful
if resp.StatusCode != http.StatusOK {
fmt.Printf("Login failed, status code = %d\n", resp.StatusCode)
return client, fmt.Errorf("Login failed, status code = %d\n", resp.StatusCode)
}
fmt.Println("Login successful")

return client, nil
}
19 changes: 10 additions & 9 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,22 @@ import (

// initializeClient initializes and returns an http.Client with a cookie jar.
// The cookie jar is used to store and manage cookies for subsequent requests.

// Returns:
// - http.Client: The initialized http.Client with the cookie jar.
func InitializeClient() http.Client {
func InitializeClient() (http.Client, error) {
// Initialize cookie jar
jar, err := cookiejar.New(nil)
if err != nil {
log.Fatal(err)
}

// Initialize client
client := http.Client{
if err == nil {
// no error create client
client := http.Client{
Jar: jar,
}
return client, nil
} else {
// error creating cookie jar
return http.Client{}, err
}

return client
}

// GetLoginPage sends a GET request to the specified baseURL + loginRoute and returns the parsed HTML document and any error encountered.
Expand Down
74 changes: 15 additions & 59 deletions config/config.go
Original file line number Diff line number Diff line change
@@ -1,81 +1,37 @@
package config

import (
"log"
"net/url"
"os"

log "github.com/charmbracelet/log"
"github.com/joho/godotenv"
)

func GenerateLoginURLValuesFromENV(csrfToken string) (loginData url.Values, err error) {
loginData = url.Values{
"user": {GetUsernameFromENV()},
"password": {GetPasswordFromENV()},
"_csrf": {csrfToken},
}
if loginData.Get("user") == "" || loginData.Get("password") == "" {
return loginData, err

func init() {
if err := godotenv.Load(); err != nil {
log.Fatal("No .env file found")
}
return loginData, nil
}

func GetUsernameFromENV() (username string) {
err := godotenv.Load()
if err != nil {
log.Fatal("Error loading .env file")
}
return os.Getenv("USERNAME")
func GetIDFromENV() string {
return os.Getenv("ID")
}

func GetPasswordFromENV() string {
err := godotenv.Load()
if err != nil {
log.Fatal("Error loading .env file")
}
return os.Getenv("PASSWORD")
}

func SetUsernameInENV(username string) {
err := godotenv.Load()
if err != nil {
log.Fatal("Error loading .env file")
}
os.Setenv("USERNAME", username)
}

func SetPasswordInENV(password string) {
err := godotenv.Load()
if err != nil {
log.Fatal("Error loading .env file")
}
os.Setenv("PASSWORD", password)
}

func GenerateENVFile() {
f, err := os.Create(".env")
if err != nil {
log.Fatal(err)
}
defer f.Close()

_, err = f.WriteString("USERNAME=\nPASSWORD=")
if err != nil {
log.Fatal(err)
}
}

func DoesENVFileExist() bool {
if _, err := os.Stat(".env"); os.IsNotExist(err) {
return false
func GenerateLoginURLValuesFromENV(csrfToken string) (loginData url.Values, err error) {
loginData = url.Values{
"user": {GetIDFromENV()},
"password": {GetPasswordFromENV()},
"_csrf": {csrfToken},
}
return true
}
log.Debug("Login Data", "loginData", loginData)
if loginData.Get("user") == "" || loginData.Get("password") == "" {
return loginData, err

func IsENVFileEmpty() bool {
if GetUsernameFromENV() == "" || GetPasswordFromENV() == "" {
return true
}
return false
return loginData, nil
}
7 changes: 5 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@ require (
github.com/charmbracelet/bubbles v0.16.1
github.com/charmbracelet/bubbletea v0.24.2
github.com/charmbracelet/lipgloss v0.9.1
github.com/joho/godotenv v1.5.1
github.com/charmbracelet/log v0.3.1
)

require (
github.com/andybalholm/cascadia v1.3.1 // indirect
github.com/atotto/clipboard v0.1.4 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/joho/godotenv v1.5.1 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-isatty v0.0.18 // indirect
github.com/mattn/go-localereader v0.0.1 // indirect
Expand All @@ -24,9 +26,10 @@ require (
github.com/muesli/reflow v0.3.0 // indirect
github.com/muesli/termenv v0.15.2 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
golang.org/x/net v0.7.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.12.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/term v0.6.0 // indirect
golang.org/x/text v0.7.0 // indirect
)
18 changes: 16 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,14 @@ github.com/charmbracelet/bubbletea v0.24.2 h1:uaQIKx9Ai6Gdh5zpTbGiWpytMU+CfsPp06
github.com/charmbracelet/bubbletea v0.24.2/go.mod h1:XdrNrV4J8GiyshTtx3DNuYkR1FDaJmO3l2nejekbsgg=
github.com/charmbracelet/lipgloss v0.9.1 h1:PNyd3jvaJbg4jRHKWXnCj1akQm4rh8dbEzN1p/u1KWg=
github.com/charmbracelet/lipgloss v0.9.1/go.mod h1:1mPmG4cxScwUQALAAnacHaigiiHB9Pmr+v1VEawJl6I=
github.com/charmbracelet/log v0.3.1 h1:TjuY4OBNbxmHWSwO3tosgqs5I3biyY8sQPny/eCMTYw=
github.com/charmbracelet/log v0.3.1/go.mod h1:OR4E1hutLsax3ZKpXbgUqPtTjQfrh1pG3zwHGWuuq8g=
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 h1:q2hJAaP1k2wIvVRd/hEHD7lacgqrCPS+k8g1MndzfWY=
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
Expand All @@ -33,12 +39,18 @@ github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
Expand All @@ -59,8 +71,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
Expand All @@ -76,3 +88,5 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Binary file modified main
Binary file not shown.
50 changes: 34 additions & 16 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ package main

import (
// local packages
"log"
"os"
"themis-cli/auth"
"themis-cli/client"
"themis-cli/config"
"themis-cli/tree"
"themis-cli/ui"

log "github.com/charmbracelet/log"
)

const (
Expand All @@ -20,53 +21,70 @@ const (
)

func main() {
logger := log.New(os.Stderr)
logger.SetReportTimestamp(false)
logger.SetReportCaller(false)
logger.SetLevel(log.DebugLevel)

ui.GetLoginCredientialsFromTUI(false)
httpClient, err := client.InitializeClient()

if err != nil {
logger.Fatal(err)
return
} else {
logger.Debug("httpClient initialized 🔥 :", "objectinfo", httpClient)
}

httpClient := client.InitializeClient()
// the goquery document represents the parsed HTML document of the login page (baseURL + loginRoute)
document, err := client.GetLoginPage(httpClient, baseURL, loginRoute)
if err != nil {
log.Fatal(err)
logger.Fatal(err)
return
} else {
logger.Debug("document initialized 🔥 :", "objectinfo", document)
}

// get csrfToken from login page
csrfToken, err := auth.GetCsrfToken(document)
if err != nil {
log.Fatal(err)
logger.Fatal(err)
return
} else {
logger.Debug("csrfToken 🍪 :", "objectinfo", csrfToken)
}

// generate loginData from ENV variables and csrfToken
// loginData is a url.Values object that contains the login data for the Themis login form
loginData, err := config.GenerateLoginURLValuesFromENV(csrfToken)
if err != nil {
log.Fatal(err)
logger.Fatal(err)
return
} else {
logger.Debug("LoginData 🔒 :", "user", loginData.Get("user"), "password", loginData.Get("password"))
}

// login to Themis and get the authenticated http.Client
httpClient, err = auth.Login(httpClient, baseURL+loginRoute, loginData)
if err != nil {
log.Fatal(err)
logger.Fatal(err)
return
} else {
logger.Debug("httpClient authenticated 😎 :", "objectinfo", httpClient)
}

// get user data

name := client.GetFullName(&httpClient, baseURL)
log.Default().Println(name)
email := client.GetEmail(&httpClient, baseURL)
log.Default().Println(email)
lastLoggedIn := client.GetLastLoggedIn(&httpClient, baseURL)
log.Default().Println(lastLoggedIn)
firstLoggedIn := client.GetFirstLoggedIn(&httpClient, baseURL)
log.Default().Println(firstLoggedIn)

logger.Info("UserData 🥸 :", "name", name, "email", email, "lastLoggedIn", lastLoggedIn, "firstLoggedIn", firstLoggedIn)

URL := "https://themis.housing.rug.nl/course/2023-2024/progfun/"
rootNode := tree.BuildRootAssignmentNode("root", URL)
rootNode, err = tree.PullAssignmentsFromThemisAndBuildTree(&httpClient, URL, rootNode, 2)
rootNode := tree.BuildRootAssignmentNode("root", URL, logger)
rootNode, err = tree.PullAssignmentsFromThemisAndBuildTree(&httpClient, URL, rootNode, 0, logger)
if err != nil {
log.Fatal(err)
return
}
log.Default().Println(rootNode.Name)
}
23 changes: 11 additions & 12 deletions tree/tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ package tree

import (
"fmt"
"log"
"net/http"
"themis-cli/parser"

log "github.com/charmbracelet/log"
)

const (
Expand All @@ -22,16 +22,16 @@ type AssignmentNode struct {

// AppendChild appends a child node to the parent node.
// It sets the parent of the child node and adds the child node to the parent's list of children.
func (n *AssignmentNode) AppendChild(c *AssignmentNode) {
log.Default().Println(fmt.Sprintf("Appending child %s to parent %s", c.Name, n.Name))
func (n *AssignmentNode) AppendChild(c *AssignmentNode, logger *log.Logger) {
logger.Debug("Appending child", "child", c.Name, "parent", n.Name)
c.Parent = n
n.children = append(n.children, c)
}

// BuildAssignmentNode creates a new AssignmentNode with the specified parent, name, and URL.
// It logs a message indicating the node being built and returns the created node.
func BuildAssignmentNode(parent *AssignmentNode, name string, url string) *AssignmentNode {
log.Default().Println(fmt.Sprintf("Building node %s", name))
func BuildAssignmentNode(parent *AssignmentNode, name string, url string, logger *log.Logger) *AssignmentNode {
logger.Debug("Building node", "name", name, "url", url)
node := &AssignmentNode{
Name: name,
URL: url,
Expand All @@ -42,12 +42,11 @@ func BuildAssignmentNode(parent *AssignmentNode, name string, url string) *Assig

// BuildRootAssignmentNode creates a root assignment node with the given name and URL.
// It calls the BuildAssignmentNode function with a nil parent node.
func BuildRootAssignmentNode(name string, url string) *AssignmentNode {
return BuildAssignmentNode(nil, name, url)
func BuildRootAssignmentNode(name string, url string, logger *log.Logger) *AssignmentNode {
return BuildAssignmentNode(nil, name, url, logger)
}

func PullAssignmentsFromThemisAndBuildTree(client *http.Client, URL string, rootNode *AssignmentNode, depth int) (*AssignmentNode, error) {

func PullAssignmentsFromThemisAndBuildTree(client *http.Client, URL string, rootNode *AssignmentNode, depth int, logger *log.Logger) (*AssignmentNode, error) {
// get assignments on page
assignments, err := parser.GetAssignmentsOnPage(client, URL)
if err != nil {
Expand All @@ -56,13 +55,13 @@ func PullAssignmentsFromThemisAndBuildTree(client *http.Client, URL string, root

// build assignment nodes
for _, assignment := range assignments {
assignmentNode := BuildAssignmentNode(rootNode, assignment["name"], assignment["url"])
rootNode.AppendChild(assignmentNode)
assignmentNode := BuildAssignmentNode(rootNode, assignment["name"], assignment["url"], logger)
rootNode.AppendChild(assignmentNode, logger)

// build tree
if depth > 0 {
for _, child := range rootNode.children {
child, err = PullAssignmentsFromThemisAndBuildTree(client, child.URL, child, depth-1)
child, err = PullAssignmentsFromThemisAndBuildTree(client, child.URL, child, depth-1, logger)
if err != nil {
return nil, fmt.Errorf("error building tree: %v", err)
}
Expand Down
Loading

0 comments on commit 0de4020

Please sign in to comment.