Giter Site home page Giter Site logo

the-dr-lazy / cascade Goto Github PK

View Code? Open in Web Editor NEW
21.0 3.0 0.0 1.37 MB

A project management service with pure functional programming paradigm in the heart.

License: Mozilla Public License 2.0

Haskell 93.62% Makefile 0.30% PLpgSQL 1.66% Shell 0.83% Mustache 0.11% Dhall 2.71% Nix 0.77%
haskell project-management trello cascade monday jira

cascade's Introduction

Logo

Welcome to Cascade License

A project management service just to show that real-world Haskell is awesome. project is in Work In Progress. Can you help us in develop? we are waiting for your PR (Pull Request).

Show your support

Give a โญ if this project helped you!

๐Ÿ  Homepage

Authors

Contributing

Contributions, issues and feature requests are welcome!

Please read CONTRIBUTING.md for details on our code of conduct, and the process for submitting pull requests to us. Feel free to check issues page.

Versioning

We use SemVer for versioning. For the versions available, see the tags on this repository.

๐Ÿ“ License

Copyright ยฉ 2021 Cascade (https://github.com/the-dr-lazy/cascade/).

This project is Mozilla Public License 2.0 licensed.

cascade's People

Contributors

jedimahdi avatar mehrdadlinux avatar the-dr-lazy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

cascade's Issues

Obtain PostgreSQL connection information through command line arguments

Motivation

Currently, the PostgreSQL database connection string is hardcoded into the cascade-cli package.

"postgresql://cascade:cascade@postgresql:5432/cascade"

It's practical to be able to change it when starting the API server.

Summary

Get the following options through the CLI arguments and generate the corresponding connection string:

  • --postgres-host
    • optional
    • default: localhost
  • --postgres-port
    • optional
    • default: 5432
  • --postgres-user
    • optional
    • default: cascade
  • --postgres-password
    • optional
  • --postgres-database
    • optional
    • default: cascade-api

Basic Example

$ cascade --postgres-host=localhost \
          --postgres-port=5432 \
          --postgres-user=cascade \
          --postgres-password=XXXX \
          --postgres-database=cascade-api

Implementation Details

Please

  1. Use optparse-applicative for CLI option parsing.
  2. Study The Partial Options Monoid
  3. Look at and understand Summoner.Config as an example.

Thank you.

Flags

  • I would like to submit a PR if the requested feature becomes approved (Help can be provided if you need assistance submitting a PR.).
  • Breaking change.

User and authentication endpoints

Motivation

The system needs a user and authentication API. Anonymous users should be able to register and login into the system. Authenticated users should be able to logout.

Summary

User

  • id - a UUID as an identifier of the entity.
  • username
  • email
  • passHash
  • createdAt
  • updatedAt

POST /users

Register a user.

Request Body

  • username
    • required
  • email
    • required
  • password
    • required

POST /user/login

Log-in as a registered user.

Request Body

  • username
    • required
  • password
    • required

DELETE /user/logout

Log-out as an authenticated user.
There is no need to blacklist the JWT token. Let's do not make it complicated.

Flags

  • I would like to submit a PR if the requested feature becomes approved (Help can be provided if you need assistance submitting a PR.).
  • Breaking change.

CLI version information

Motivation

It's good to know which version of cascade-cli you are working with.

Summary

The CLI should be able to understand the --version option and output the following information:

  • Version of cascade-cli package specified in cascade-cli.cabal file when building the CLI executable.
  • Git revision which CLI executable built upon it.
  • Git commit date which CLI executable built upon it.

Basic Example

$ cascade --version
Cascade CLI v0.1.0
Git revision: 53f3ffe5c469c1b3dd2d05f04cffad040a78fe3d
Last commit:  2020-12-26

Implementation Details

Please

  1. Read and understand summoner-cli version output
  2. Use optparse-applicative for CLI option parsing.
  3. Use git-rev library to retrieve git revision and the git commit date.
  4. To understand how you can access the version field in the cabal file, read about Cabal auto-generated modules on user guide under the sections Accessing data files from package code and Accessing the package version.
  5. Read how summoner access the version field.

Thank you.

Flags

  • I would like to submit a PR if the requested feature becomes approved (Help can be provided if you need assistance submitting a PR.).
  • Breaking change.

Making integration tests runnable on Linux

It looks like currently, integration tests don't run on Linux systems due to some sort of missing PostgreSQL configuration. I don't have any Linux machines in my territory and my Linux administration knowledge is limited.
So maybe someone who has the environment and knowledge can work on it.

Generic record validation and error data structure

Motivation

data RawCreatableV f = RawCreatable
{ username :: Validatable f Text (Maybe Username.ValidationErrors)
, emailAddress :: Validatable f Text (First EmailAddress.ValidationError)
, password :: Validatable f Text (Maybe Password.ValidationErrors)
}
deriving stock Generic
type RawCreatable = RawCreatableV Identity
deriving stock instance Show RawCreatable
deriving stock instance Eq RawCreatable
deriving anyclass instance FromJSON RawCreatable
deriving anyclass instance ToJSON RawCreatable
type RawCreatableValidationErrors = RawCreatableV Validate
deriving stock instance Show RawCreatableValidationErrors
deriving anyclass instance FromJSON RawCreatableValidationErrors
deriving anyclass instance ToJSON RawCreatableValidationErrors
deriving via (GenericSemigroup RawCreatableValidationErrors) instance Semigroup RawCreatableValidationErrors
deriving via (GenericMonoid RawCreatableValidationErrors) instance Monoid RawCreatableValidationErrors
data ParsedCreatable = ParsedCreatable
{ username :: Username
, emailAddress :: EmailAddress
, password :: Password
}
deriving stock (Generic, Show, Eq)
parseRawCreatableUser :: RawCreatable
-> Validation
RawCreatableValidationErrors
ParsedCreatable
parseRawCreatableUser RawCreatable {..} =
let
validateUsername = Username.mk username |> first \e ->
mempty { username = Just e } :: RawCreatableValidationErrors
validateEmailAddress = EmailAddress.mk emailAddress |> maybeToSuccess
(mempty { emailAddress = coerce $ Just EmailAddress.IsInvalid } :: RawCreatableValidationErrors
)
validatePassword = Password.mk password |> first \e ->
mempty { password = Just e } :: RawCreatableValidationErrors
in
ParsedCreatable
<$> validateUsername
<*> validateEmailAddress
<*> validatePassword

As it's obvious, making validation functions for product types with record syntax is harsh and verbose but it shouldn't be. We can use the Generic machinery of GHC to make it comfortable.

Summary

To be able to make a type-level mechanism for making validation function for product types we'll need some type information of the product type like the field name and the value type of the field. The best way to have such information at the type level is row types. Unfortunately, Haskell doesn't have row types yet. So, Generics to the rescue!

Basic Example

As an example, I'll demonstrate a form that consists of username and future fields.

Validation of username field is totally a simple pure function of type Text -> Validation ValidationErrors Username but for the sake of implementation costs we will represent it as follow:

newtype Username = Username { un :: Text }

data ValidationError = IsShort | IsLong | Invalid deriving stock Generic
type ValidationErrors = NonEmpty ValidationError

instance Validatable Username where
  type Raw Username = Text
  type Parsed Username = Username
  type Errors Username = ValidationErrors
  
  validate :: Text -> Sem '[] (Validation ValidationErrors Username)
  validate = undefined

As mentioned, there is a potential design space with the validate @Username type. As it doesn't need any effects, wrapping the whole validation in Sem looks redundant. It's not optimal but makes type-level computations simpler by now. We can reconsider having a more precise type in the future.

Validation of Future depends on an effect named TimeL:

newtype Future = Future { un :: OffsetDatetime }

data ValidationError = IsPast deriving stock Generic

instance Validatable Future where
  type Raw Future = OffsetDatetime
  type Parsed Future = Future
  type Errors Future = ValidationError
  type Effects Future = '[TimeL]
  
  validate :: OffsetDatetime -> Sem '[TimeL] (Validation ValidationError Future)
  validate = undefined

And finally the Form type:

data Form (v :: Validity) = Form
  { username :: Validate v Username
  , future   :: Validate v Future
  }
  deriving stock Generic
  deriving Validatable via (Generically (Form v))

By deriving Validatable for Form v we'll be able to validate the product type as follow:

x = validate @(Form 'Raw) Form { username = "user_name", future = 13 }

Also, the Error type of derived Validtable should have ToJSON and FromJSON instances which render to and un-render from the following JSON structure:

{ "username": [ { "tag": "IsShort", "message": "username is too short" } ] 
, "future": [ { "tag": "IsPast", "message": "future is not past!" } ]
}

Implementation Details

Please

  1. Read Generic Validation of Nested Data.

Thank you.

Flags

  • I would like to submit a PR if the requested feature becomes approved (Help can be provided if you need assistance submitting a PR.).
  • Breaking change.

Logging

Motivation

Seriously? Do you want me to explain the motivation behind logging?! It's inevitable. You'll face the music.

Summary

The logging system should introduce a Free language that helps us to put the following levels of the log into the interpreted sink.

  • ERROR
  • WARN
  • INFO
  • DEBUG

Log information:

  • Level
  • Message
  • Date & Time
  • Source location
  • Thread ID

Currently, the best sink is stdout (WARN, INFO, DEBUG) and stderr (ERROR). Let's use the power of Unix to pipe stdout and stderr wherever we want!

Basic Example

Implementation Details

Please

  1. Read Logs Are Streams, Not Files
  2. Read co-log: Composable Contravariant Combinatorial Comonadic Configurable Convenient Logging.
  3. Use co-log-polysemy for defining Free language and interpreter.

Thank you.

Flags

  • I would like to submit a PR if the requested feature becomes approved (Help can be provided if you need assistance submitting a PR.).
  • Breaking change.

Newtype deriving strategy for Show

Description

Username, EmailAddress, and Password types use newtype deriving strategy for Show instances. This was not intentional and is wrong in this case.

deriving newtype (Show, Eq, FromJSON, ToJSON)

deriving newtype (Show, Eq, FromJSON, ToJSON)

Obtain PostgreSQL connection information from environment variables

Motivation

As mentioned in #10, the PostgreSQL connection string is hardcoded in the cascade-cli package.

"postgresql://cascade:cascade@postgresql:5432/cascade"

This issue requests something similar to #10 by another route of information injection. In the development environment, it's more helpful to use environment variables to state the target PostgreSQL server and database. The CLI should be able to combine PostgreSQL connection information given by the environment variables with the CLI arguments mentioned in #10. In the case of conflicts, the CLI should prefer most local information. The CLI arguments are more local than environment variables.

Summary

Get the following environment variables and combine them with the corresponding CLI arguments mentioned in #10:

  • CASCADE_POSTGRES_HOST
    • optional
  • CASCADE_POSTGRES_PORT
    • optional
  • CASCADE_POSTGRES_USER
    • optional
  • CASCADE_POSTGRES_PASSWORD
    • optional
  • CASCADE_POSTGRES_DATABASE
    • optional

Basic Example

$ export CASCADE_POSTGRES_HOST="localhost"
$ export CASCADE_POSTGRES_PORT="5432"
$ export CASCADE_POSTGRES_USER="cascade"
$ export CASCADE_POSTGRES_PASSWORD="XXXX"
$ export CASCADE_POSTGRES_DATABASE="cascade-api"
$ cascade

Implementation Details

Please

  1. Study The Partial Options Monoid
  2. Look at and understand Summoner.Config as an example.

Thank you.

Flags

  • I would like to submit a PR if the requested feature becomes approved (Help can be provided if you need assistance submitting a PR.).
  • Breaking change.

Obtain HTTP port for starting HTTP API server from environment variables

Motivation

As mentioned in #14, API listens to port 3141 which has been hardcoded in the cascade-api package.

Warp.run 3141 $ application

This issue requests something similar to #14 by another route of information injection.

Summary

Get the CASCADE_HTTP_PORT environment variable and combine it with the corresponding CLI argument (--http-port) mentioned in #14:

  • CASCADE_HTTP_PORT
    • optional

In the case of conflict, the CLI should prefer most local information. The CLI arguments are more local than environment variables.

Basic Example

$ export CASCADE_HTTP_PORT=3141
$ cascade

Implementation Details

Please

  1. Study The Partial Options Monoid
  2. Look at and understand Summoner.Config as an example.

Thank you.

Flags

  • I would like to submit a PR if the requested feature becomes approved (Help can be provided if you need assistance submitting a PR.).
  • Breaking change.

Obtain HTTP port for starting API HTTP server via command line arguments

Motivation

Currently, API listens to port 3141 which has been hardcoded in the cascade-api package.

Warp.run 3141 $ application

The user should be able to change this port number via Cascade CLI.

Summary

CLI gets a --http-port option and checks its availability. If it was available, start the API server with the given port number.

  • --http-port
    • optional
    • default: 3141

The default port number of Cascade API defines by Pi number (3.141...).

Basic Example

$ cascade --http-port=3141

Implementation Details

Please

  1. Use optparse-applicative for CLI option parsing.

Thank you.

Flags

  • I would like to submit a PR if the requested feature becomes approved (Help can be provided if you need assistance submitting a PR.).
  • Breaking change.

Tasks endpoints

Motivation

Every project is able to contain zero or more tasks. Users should be able to create, retrieve, update, and delete task(s) for every project.

Summary

Task

  • id - a UUID as an identifier of the entity.
  • title
  • deadlineAt - deadline date-time.
  • projectId - the project to which the task belongs to.

POST /projects/:id/tasks

Creates a task and returns it.

Request Body

  • title
    • required.
  • deadlineAt
    • required.
    • should be a date-time in the future.

GET /projects/:id/tasks

Lists all tasks which belong to the given project ID.

GET /tasks/:id

Lookup for a task by the given ID.

PATCH /tasks/:id

Selectively update a task by the given ID and returns the updated task.

  • title
    • optional.
  • deadlineAt
    • optional.
    • should be a date-time in the future.

DELETE /tasks/:id

Delete a task by the given ID and returns it.

Implementation Details

Please

  1. Parse, don't validate.
  2. Use validation-selective for Validation datatype.
  3. Use chronos as the time library.
  4. Add the corresponding state machine tests.

Thank you.

Flags

  • I would like to submit a PR if the requested feature becomes approved (Help can be provided if you need assistance submitting a PR.).
  • Breaking change.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.