Skip to content
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
32 changes: 30 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Keep It Up

A simple system that keeps an activity alive through periodic interaction and triggers an alert when it is left unattended for too long.
A system that coordinates periodic interactions across multiple devices and tracks when the next interaction is required.

## Tech Stack

Expand All @@ -10,7 +10,35 @@ Go + SQLite
Echo + SQLC + Goose
```

## API
## CLI Management

```text
Usage:
keepitup <noun> <verb> [args...]

Nouns:
game add <name>
update <id> <name>
delete <id>
access grant <gameId> <playerId>
revoke <gameId> <playerId>
player add <name> <username> <password>
rename <id> <name>
passwd <id> <currentPassword> <newPassword>
passwd-force <id> <password>
delete <id>
auth validate-passwd <password>
hash-passwd <password>
check-passwd <username> <password>
data games <playerId>
shared <gameId>
interactions <gameId> <count>
session save <gameId> <playerId> <RFC3339 timestamp>
resume <gameId> <playerId>
pause <gameId> <playerId>
```

## HTTP API

```text
POST /login username + password → set cookies
Expand Down
8 changes: 6 additions & 2 deletions internal/application/usecase/authentication.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
"keep-it-up/internal/core/model"
"keep-it-up/internal/infrastructure/database"
"strings"

Expand Down Expand Up @@ -71,6 +72,9 @@ func (uc *Authentication) CheckPlayerPassword(ctx context.Context, username stri
return true, nil
}

func (uc *Authentication) LoginPlayer(ctx context.Context, username string, password string) {

func (uc *Authentication) LoginPlayer(
ctx context.Context, username string, password string,
) (model.AuthResult, error) {
// TODO: Implement
return model.AuthResult{}, nil
}
2 changes: 1 addition & 1 deletion internal/application/usecase/data_fetching.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ func NewDataFetching() *DataFetching {
}

func (uc *DataFetching) ListPlayerGames(
ctx context.Context, gameId int64, playerId int64,
ctx context.Context, playerId int64,
) ([]database.Game, error) {
return nil, nil
}
Expand Down
4 changes: 2 additions & 2 deletions internal/core/interface/driver/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ type Authentication interface {
IsPasswordValid(password string) error
GeneratePasswordHash(password string) (string, error)
CheckPlayerPassword(ctx context.Context, username string, password string) (bool, error)
LoginPlayer(ctx context.Context, username string, password string)
LoginPlayer(ctx context.Context, username string, password string) (model.AuthResult, error)
}

type DataFetching interface {
ListPlayerGames(ctx context.Context, gameId int64, playerId int64) ([]database.Game, error)
ListPlayerGames(ctx context.Context, playerId int64) ([]database.Game, error)
GetSharedData(ctx context.Context, gameId int64) (model.SharedData, error)
ListInteractions(ctx context.Context, gameId int64, count int) ([]database.Interaction, error)
}
Expand Down
10 changes: 9 additions & 1 deletion internal/core/model/model.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package model

import "time"
import (
"keep-it-up/internal/infrastructure/database"
"time"
)

type SharedDataStatus string

Expand All @@ -17,3 +20,8 @@ type SharedData struct {
LastSavedAt *time.Time
LastPausedAt *time.Time
}

type AuthResult struct {
Token string
Player database.Player
}
45 changes: 19 additions & 26 deletions internal/infrastructure/driver/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ var (
ErrWrongArgCount = errors.New("wrong number of arguments")
)

const usage = `keep-it-up — system management CLI
const usage = `keepitup --- system management CLI

Usage:
keep-it-up <noun> <verb> [args...]
keepitup <noun> <verb> [args...]

Nouns:
game add <name>
Expand All @@ -38,18 +38,15 @@ Nouns:
passwd <id> <currentPassword> <newPassword>
passwd-force <id> <password>
delete <id>
auth validate-password <password>
hash-password <password>
check-password <username> <password>
data games <gameId> <playerId>
auth validate-passwd <password>
hash-passwd <password>
check-passwd <username> <password>
data games <playerId>
shared <gameId>
interactions <gameId> <count>
session save <gameId> <playerId> <RFC3339 timestamp>
resume <gameId> <playerId>
pause <gameId> <playerId>

Note: player login is not exposed here; it belongs to an interactive/session
driver, not an administrative one.
`

// Deps groups the driver ports and I/O streams the CLI needs. It is a
Expand Down Expand Up @@ -320,34 +317,34 @@ func (c *CLI) runAuth(ctx context.Context, args []string) error {
}
verb, rest := args[0], args[1:]
switch verb {
case "validate-password":
case "validate-passwd":
if len(rest) != 1 {
return wrongArgs("auth validate-password", "auth validate-password <password>")
return wrongArgs("auth validate-passwd", "auth validate-passwd <password>")
}
if err := c.d.Auth.IsPasswordValid(rest[0]); err != nil {
return fmt.Errorf("auth validate-password: %w", err)
return fmt.Errorf("auth validate-passwd: %w", err)
}
fmt.Fprintln(c.d.Stdout, "valid")
return nil

case "hash-password":
case "hash-passwd":
if len(rest) != 1 {
return wrongArgs("auth hash-password", "auth hash-password <password>")
return wrongArgs("auth hash-passwd", "auth hash-passwd <password>")
}
hash, err := c.d.Auth.GeneratePasswordHash(rest[0])
if err != nil {
return fmt.Errorf("auth hash-password: %w", err)
return fmt.Errorf("auth hash-passwd: %w", err)
}
fmt.Fprintln(c.d.Stdout, hash)
return nil

case "check-password":
case "check-passwd":
if len(rest) != 2 {
return wrongArgs("auth check-password", "auth check-password <username> <password>")
return wrongArgs("auth check-passwd", "auth check-passwd <username> <password>")
}
ok, err := c.d.Auth.CheckPlayerPassword(ctx, rest[0], rest[1])
if err != nil {
return fmt.Errorf("auth check-password: %w", err)
return fmt.Errorf("auth check-passwd: %w", err)
}
fmt.Fprintln(c.d.Stdout, ok)
return nil
Expand All @@ -366,18 +363,14 @@ func (c *CLI) runData(ctx context.Context, args []string) error {
verb, rest := args[0], args[1:]
switch verb {
case "games":
if len(rest) != 2 {
return wrongArgs("data games", "data games <gameId> <playerId>")
}
gameID, err := parseID(rest[0])
if err != nil {
return fmt.Errorf("data games: %w", err)
if len(rest) != 1 {
return wrongArgs("data games", "data games <playerId>")
}
playerID, err := parseID(rest[1])
playerID, err := parseID(rest[0])
if err != nil {
return fmt.Errorf("data games: %w", err)
}
games, err := c.d.Data.ListPlayerGames(ctx, gameID, playerID)
games, err := c.d.Data.ListPlayerGames(ctx, playerID)
if err != nil {
return fmt.Errorf("data games: %w", err)
}
Expand Down
Loading