Ver Fonte

implement user management API

Mike há 2 anos atrás
pai
commit
3ad366ec91
4 ficheiros alterados com 147 adições e 3 exclusões
  1. 46 0
      api.yml
  2. 2 0
      cmd/main.go
  3. 36 3
      server/feedbag_store.go
  4. 63 0
      server/mgmt_api.go

+ 46 - 0
api.yml

@@ -0,0 +1,46 @@
+openapi: 3.0.3
+info:
+  title: User Management API
+  description: API to manage user accounts with screen names and passwords
+  version: 1.0.0
+paths:
+  /user:
+    get:
+      summary: Get all users
+      description: Retrieve a list of all user accounts without passwords.
+      responses:
+        '200':
+          description: Successful response containing a list of users without passwords.
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: '#/components/schemas/User'
+    post:
+      summary: Create a new user
+      description: Create a new user account with a screen name and password.
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/User'
+      responses:
+        '201':
+          description: User account created successfully.
+        '400':
+          description: Bad request. Invalid input data.
+components:
+  schemas:
+    User:
+      type: object
+      properties:
+        screen_name:
+          type: string
+          description: The user's screen name.
+        password:
+          type: string
+          description: The user's password.
+          readOnly: true
+          format: password

+ 2 - 0
cmd/main.go

@@ -22,6 +22,8 @@ func main() {
 		log.Fatal(err)
 	}
 
+	go server.StartManagementAPI(fm)
+
 	sm := server.NewSessionManager()
 	cr := server.NewChatRegistry()
 

+ 36 - 3
server/feedbag_store.go

@@ -67,9 +67,9 @@ func NewStubUser(screenName string) (User, error) {
 }
 
 type User struct {
-	ScreenName string
-	AuthKey    string
-	PassHash   []byte
+	ScreenName string `json:"screen_name"`
+	AuthKey    string `json:"-"`
+	PassHash   []byte `json:"-"`
 }
 
 func (u *User) HashPassword(passwd string) error {
@@ -95,6 +95,30 @@ type FeedbagStore struct {
 	db *sql.DB
 }
 
+func (f *FeedbagStore) Users() ([]*User, error) {
+	q := `SELECT ScreenName FROM user`
+	rows, err := f.db.Query(q)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	var users []*User
+	for rows.Next() {
+		u := &User{}
+		if err := rows.Scan(&u.ScreenName); err != nil {
+			return nil, err
+		}
+		users = append(users, u)
+	}
+
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+
+	return users, nil
+}
+
 func (f *FeedbagStore) GetUser(screenName string) (*User, error) {
 	q := `
 		SELECT 
@@ -112,6 +136,15 @@ func (f *FeedbagStore) GetUser(screenName string) (*User, error) {
 	return u, err
 }
 
+func (f *FeedbagStore) InsertUser(u User) error {
+	q := `
+		INSERT INTO user (ScreenName, authKey, passHash)
+		VALUES (?, ?, ?)
+	`
+	_, err := f.db.Exec(q, u.ScreenName, u.AuthKey, u.PassHash)
+	return err
+}
+
 func (f *FeedbagStore) UpsertUser(u User) error {
 	q := `
 		INSERT INTO user (ScreenName, authKey, passHash)

+ 63 - 0
server/mgmt_api.go

@@ -0,0 +1,63 @@
+package server
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/http"
+)
+
+func StartManagementAPI(fs *FeedbagStore) {
+	http.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
+		switch r.Method {
+		case http.MethodGet:
+			getUsers(fs, w, r)
+		case http.MethodPost:
+			createUser(fs, w, r)
+		default:
+			http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
+		}
+	})
+
+	port := 8080
+	fmt.Printf("Server is running on :%d...\n", port)
+	if err := http.ListenAndServe(fmt.Sprintf(":%d", port), nil); err != nil {
+		panic(err)
+	}
+}
+
+// getUsers handles the GET /user endpoint.
+func getUsers(fs *FeedbagStore, w http.ResponseWriter, r *http.Request) {
+	w.Header().Set("Content-Type", "application/json")
+	users, err := fs.Users()
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+	if err := json.NewEncoder(w).Encode(users); err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+}
+
+type CreateUser struct {
+	User
+	Password string `json:"password,omitempty"`
+}
+
+// createUser handles the POST /user endpoint.
+func createUser(fs *FeedbagStore, w http.ResponseWriter, r *http.Request) {
+	var newUser CreateUser
+	if err := json.NewDecoder(r.Body).Decode(&newUser); err != nil {
+		http.Error(w, err.Error(), http.StatusBadRequest)
+		return
+	}
+
+	newUser.HashPassword(newUser.Password)
+	if err := fs.InsertUser(newUser.User); err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+
+	w.WriteHeader(http.StatusCreated)
+	fmt.Fprintln(w, "User account created successfully.")
+}