ditt

package module
v0.0.0-...-4c9ae48 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 6, 2021 License: Apache-2.0 Imports: 25 Imported by: 0

README

Data Impact Technical Test

Solution to the technical test

Install and build

git clone https://github.com/omecodes/ditt
cd ditt

go get -v -t -d ./...
cd bin

make

chmod u+x ditt-api-server

Run

Assuming you are in the bin folder, run the following command:

./ditt-api-server start --port=8080
Database target

By default, the program target a mongo database running at localhost. If you want it to connect to another mongo database you can specify it this way:

./ditt-api-server start --port=8080 --db-uri=<target-db-uri>

Comments

Testing

The API is pretty well covered. Tests for implementations of UserDataStore and Files are the big absents but this is due to lack of time.

Specification

Some part of the specification were not very clear to me. Maybe it'll be discussed during our next call

Difficulties

I spent time reading about routine/channels and Mongo. About Mongo, I tried up to 2 different go implementations.

Documentation

Index

Constants

View Source
const (

	// LoginEndpoint is the HTTP API endpoint to initialise an authenticated session
	LoginEndpoint = "/login"

	// AddUsersEndpoint is the HTTP API endpoint to add users
	AddUsersEndpoint = "/add/users"

	// DeleteUserEndpoint is the HTTP API endpoint to delete data of a user
	DeleteUserEndpoint = "/delete/user/{id}"

	// GetUserEndpoint is the HTTP API endpoint to get user data
	GetUserEndpoint = "/user/{id}"

	// ListUsersEndpoint is the HTTP API endpoint to add users
	ListUsersEndpoint = "/users/list"

	// UpdateUserEndpoint is the HTTP API endpoint to add users
	UpdateUserEndpoint = "/user/{id}"
)
View Source
const (
	DefaultUserListCount = 5
)

Variables

View Source
var (
	BadInput               = errors.New("bad input")
	AuthenticationRequired = errors.New("authentication required")
	Forbidden              = errors.New("forbidden")
	NotAuthorized          = errors.New("not authorized")
	NotFound               = errors.New("not found")
	Internal               = errors.New("internal")
)
View Source
var Env = struct {
	DataStore     UserDataStore
	Files         Files
	AdminPassword string
	CookiesStore  sessions.Store
}{
	DataStore:    NewUserDataMemoryStore(),
	Files:        NewMemoryFiles(),
	CookiesStore: sessions.NewCookieStore(),
}

Functions

func ContextWithLoggedUser

func ContextWithLoggedUser(parent context.Context, loggedUser string) context.Context

ContextWithLoggedUser creates a new context that holds loggedUser in addition of the parent values

func GetLoggedUser

func GetLoggedUser(ctx context.Context) string

GetLoggedUser extracts logged user name from context values

func HandleHttpAddUsersRequest

func HandleHttpAddUsersRequest(w http.ResponseWriter, r *http.Request)

HandleHttpAddUsersRequest initializes an APIHandler and calls its APIHandler.AddUsers with the request body content The request body content is expected to be an encoded JSON object list

func HandleHttpDeleteUserRequest

func HandleHttpDeleteUserRequest(w http.ResponseWriter, r *http.Request)

HandleHttpDeleteUserRequest initializes an APIHandler and calls its APIHandler.DeleteUser with userId extracted from the request URI path

func HandleHttpGetUserListRequest

func HandleHttpGetUserListRequest(w http.ResponseWriter, r *http.Request)

HandleHttpGetUserListRequest initializes an APIHandler and calls its APIHandler.GetUserList "r" is expected to be a POST request with an encoded JSON object list as body The returned value by GetUserList is set as the HTTP response body

func HandleHttpGetUserRequest

func HandleHttpGetUserRequest(w http.ResponseWriter, r *http.Request)

HandleHttpGetUserRequest initializes an APIHandler and calls its APIHandler.GetUser with userId extracted from the request URI path The returned value by GetUser is set as the HTTP response body

func HandleHttpLoginRequest

func HandleHttpLoginRequest(w http.ResponseWriter, r *http.Request)

HandleHttpLoginRequest initializes an APIHandler and calls its APIHandler.Login method with user credentials parsed from the request body

func HandleHttpUpdateUserRequest

func HandleHttpUpdateUserRequest(w http.ResponseWriter, r *http.Request)

HandleHttpUpdateUserRequest initializes an APIHandler and calls its APIHandler.UpdateUser with userId extracted from the request URI path and the request content body. The request body content is expected to be a JSON encoded UserData object

func Serve

func Serve(config *Config) error

Types

type APIHandler

type APIHandler interface {

	// Login creates an authenticated session if credentials match a registered user
	Login(ctx context.Context, username string, password string) (bool, error)

	// AddUsers parses user data list from the "reader" stream and store them in the database
	AddUsers(ctx context.Context, reader io.Reader) error

	// DeleteUser deletes the user identified by "userId' from the database
	DeleteUser(ctx context.Context, userId string) error

	// GetUser retrieves the data of the user identified by "userId"
	GetUser(ctx context.Context, userId string) (UserData, error)

	// GetUserList retrieves a set of users from the database
	GetUserList(ctx context.Context, opts ListOptions) (*UserDataList, error)

	// UpdateUser updates the data of the user identified by "userId"
	UpdateUser(ctx context.Context, userId string, userData UserData) error
}

func NewAPIHandler

func NewAPIHandler() (handler APIHandler)

NewAPIHandler constructs an API handler pipe

type BaseHandler

type BaseHandler struct {
	Next APIHandler
}

BaseHandler defines a API calls handling pipe

func (*BaseHandler) AddUsers

func (b *BaseHandler) AddUsers(ctx context.Context, reader io.Reader) error

func (*BaseHandler) DeleteUser

func (b *BaseHandler) DeleteUser(ctx context.Context, userId string) error

func (*BaseHandler) GetUser

func (b *BaseHandler) GetUser(ctx context.Context, userId string) (UserData, error)

func (*BaseHandler) GetUserList

func (b *BaseHandler) GetUserList(ctx context.Context, opts ListOptions) (*UserDataList, error)

func (*BaseHandler) Login

func (b *BaseHandler) Login(ctx context.Context, user string, password string) (bool, error)

func (*BaseHandler) UpdateUser

func (b *BaseHandler) UpdateUser(ctx context.Context, userId string, userData UserData) error

type ConcurrentUserDataProcessingRunner

type ConcurrentUserDataProcessingRunner struct {
	Provider            UserDataProvider
	Processor           UserDataProcessor
	TasksResultsSignals chan<- chan UserDataProcessingResult
	ResultSignal        chan<- chan error
}

ConcurrentUserDataProcessingRunner starts a routine. And for each provided UserData calls the callback and returns the result to the caller through the "results" channel

func (ConcurrentUserDataProcessingRunner) Run

type Config

type Config struct {
	Port      int `json:"port"`
	TlsConfig *tls.Config
}

type Files

type Files interface {
	Save(userId string, data string) error
	Delete(userId string) error
	Get(userId string) (string, error)
}

Files is a convenience for UserData file persistence

func NewDirFiles

func NewDirFiles(rootDir string) Files

func NewMemoryFiles

func NewMemoryFiles() Files

type ListOptions

type ListOptions struct {
	Offset int `json:"offset"`
	Count  int `json:"count"`
}

ListOptions defines a range limit

type UserData

type UserData string

UserData wraps string for readability

func (UserData) Data

func (d UserData) Data() string

Data retrieves the value of the "data" field

func (UserData) Id

func (d UserData) Id() string

func (UserData) Password

func (d UserData) Password() string

Password retrieves the value of the "password" field

type UserDataCallback

type UserDataCallback func(UserData) error

UserDataCallback is function that handle a UserData

type UserDataList

type UserDataList struct {
	Offset       int        `json:"offset"`
	UserDataList []UserData `json:"user_data_list"`
}

UserDataList holds info about a range of UserData objects

type UserDataProcessingResult

type UserDataProcessingResult struct {
	Err    error
	UserId string
	Data   UserData
}

UserDataProcessingResult holds info about UserData processing result

type UserDataProcessor

type UserDataProcessor interface {
	ProcessData(data UserData) (UserData, error)
}

UserDataProcessor is a convenience for user data processor

type UserDataProcessorFunc

type UserDataProcessorFunc func(data UserData) (UserData, error)

UserDataProcessorFunc is a function that implements of UserDataProcessor

func (UserDataProcessorFunc) ProcessData

func (f UserDataProcessorFunc) ProcessData(data UserData) (UserData, error)

type UserDataProvider

type UserDataProvider func(callback UserDataCallback) error

type UserDataStore

type UserDataStore interface {

	// Save saves user data
	Save(data UserData) error

	// Delete deletes the userData matching the given id
	Delete(id string) error

	// Get retrieves userData matching the given id
	Get(id string) (UserData, error)

	// ListForUser fetches a range of UserData that matches the userId
	// and pass each pass each parsed userdata to the callback
	ListForUser(userId string, offset, count int, callback UserDataCallback) error

	// List fetches a range of UserData and pass each pass each
	// parsed userdata to the callback
	List(offset, count int, callback UserDataCallback) error
}

UserDataStore is a convenience for UserData persistence management

func NewMongoUserDataStore

func NewMongoUserDataStore(uri string) (UserDataStore, error)

func NewUserDataMemoryStore

func NewUserDataMemoryStore() UserDataStore

NewUserDataMemoryStore constructs a memory based UserDataStore

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL