Giter VIP home page Giter VIP logo

townhall's Introduction

TownHall

Discord Build Clippy Formatter

Collab Strategy and Knowledge Sharing

TownHall is collaborative project for novice-to-intermediate Rust developers. We’re learning-by-doing together, in the making of a community platform modeled after the likes of Reddit space oriented and X (formerly Twitter) microblogging platform.

The project leader and default mentor for new contributors is @EstebanBorai. New mentors and mentees alike are always welcome!

Development

Requirements

Getting Started

# install just command runner
cargo install just

# clone this repository
git clone https://github.com/whizzes/townhall.git


# step into repository directory
cd ./townhall

# open a termital window and spin up Docker Containers
just dev

# create a new terminal window and run database migrations
just prepare

# execute the server (next time you just run this command)
cargo run serve

Note: As of today migrations runs when bootstrapping the server automatically

To read the documentation of the web here

Software Architecture

Layers

Client traffic is handled by a GraphQL endpoint, domain logic is exposed through services which encapsulate access to the database logic. The CLI solution communicates directly to the services.

softarq

Design

This project takes some inspiration on Domain Driven Design, but does not implements its concepts completely. Concepts like value object, model, repositories and services are present but are not 100% accurate to the original Domain Driven Design architecture.

Modules

The client and server solution is available in this repository.

Directory Description
crates/ Contains GraphQL Server Logic, CLI and Domain libraries. Rust is the predominant language.
crates/cli CLI used to manage the Server instance. run database migrations and other developer tasks
crates/core Domain Logic, includes Models, Value Objects, Repositories and Services
crates/entity Entities generated from database
crates/migration Database migrations
crates/server HTTP Server Logic, uses Axum and GraphQL
crates/test E2E Tests for the GraphQL Server
crates/web Web UI, written in Leptos

Testing

Running E2E Tests

E2E Tests run by default on a different database, this allow us to have a database for development and another for testing, speeding up the development process.

The dedicated E2E Database will be builded along with other containers when running just dev.

You can also execute a single E2E Test by specifying the name of the test function along with the just e2e_tests command:

just e2e_tests my_super_test_function_name

To run every test just execute:

just e2e_test

Teardown containers using just undev.

Contributors

Esteban Borai
Esteban Borai

💻
Michael Liendo
Michael Liendo

💻
David Arenas
David Arenas

💻
CudiLala
Cudi Lala

💻
Paly Zambrano
Paly Zambrano

💻
Phosphorus-M
Phosphorus-M

💻
David Rodriguez
David Rodríguez

💻

License

Licensed under the MIT License

townhall's People

Contributors

estebanborai avatar michael-liendo avatar dependabot[bot] avatar dave136 avatar cudidotdev avatar harshmangalam avatar palyzambrano avatar dararod avatar erlend-sh avatar phosphorus-m avatar

Stargazers

Chiko avatar koopa avatar Victor Adrian Buica avatar Bryan Maina avatar wood avatar Juan Cruz Francitorra avatar  avatar  avatar Renato avatar gabriel_ramos avatar Geoffrey Mureithi avatar Hiroto Funakoshi avatar Orhun Parmaksız avatar Nikolai Kolesnikov avatar sinfzx avatar Yasutake Kazu avatar  avatar Ever avatar Hans Bricks avatar  avatar Carlos Azpurua avatar Sonny Scroggin avatar Adoankim avatar  avatar  avatar Chetra Chann avatar  avatar Carlos Azpurua avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

townhall's Issues

Capability to create links with custom hashes

Currently links can only have a random hash.
It would be great to have links with custom hashes.


Expected Input/Output:

mutation {
  linkCreate(input: {
    url: "https://www.google.com"
    customHash: "mi_link"
  }) {
    link {
      id
      hash
      originalUrl
      expiresAt
    }
  }
}
{
  "data": {
    "linkCreate": {
      "link": {
        "id": 2,
        "hash": "mi_link",
        "originalUrl": "https://www.google.com",
        "expiresAt": "1970-01-01T00:00:00+00:00"
      }
    }
  }
}

Source Code: https://github.com/whizzes/linx/blob/main/src/server/src/graphql/link/mutation/link_create.rs#L29

Capability to Store Visit Fingerprint

Whenever a link is redirected we must store useful data for metrics purpose, for now
storing:

  • Date Time
  • User Agent

Would be enough. A fingerprint for a visit could be stored on a Link History table on a
SQL relation of 1 to Many.

Require authentication for link creation

Currently users can create links without being authenticated.
We must encourage users to have an account in order to create links, if
theres no token present in the request, or the token belongs to a deleted
user, we must not allow link creation.

Every link must have an owner_id pointing to user ID.

Comments Support

Comments are Posts where the parentId is specified.

Comments doesnt have a Title, different to regular posts.

When querying posts, comments should also be queried and paginated.

posts(first: 20, after: "post_xyz") {
  title
  content
  author {
    username
  }
  comments(first: 20) {
    content
    author {
      username
    }
  }
}

Capability to Follow Users

Capability to follow a user. This will allow users to have a personalized experience.

Tasks

Introduce the user_follow table

Introduce a user_follow table which follows the Many to Many relationship
to track user follows.

Columns would be

Name Data Type Description
IDX_ follower_followee Index PK An index made of the Follower User ID (Pxid) and Followee User ID (Pxid)
follower Pxid The ID from the user who follows
followee Pxid The ID from the user being followed by follower
created_at Timestamp Moment where the follower started following

By using the index we avoid duplicated followers

Introduce GraphQL Operations

follow(id: Pxid): Follow

Follows the user with the provided ID and returns a Follow object which contains the operation summary.

unfollow(id: Pxid): Unfollow

Unfollows the user with the provided ID and returns a Unfollow object which contains the operation summary.

Setup SQLite database using SeaORM

Setup a SQLite Database using SeaORM to store Links and Users.
This is a step forward to a new architecture where Links and Users are stored in a
relational database and frequently visited links are stored in Sled as a caching
strategy to speed up redirection.

Query with invalid filter returns unfiltered user search results

When a GraphQL query is executed using the filter in the user search and an invalid character is provided in the filter, the system incorrectly returns all users instead of displaying an empty result or handling the filter error properly.

query {
  user(filter: { username: "michael-liendo" }) {
    nodes {
      name
      email
      username
    }
  }
}

Expected Result:
The query should return an empty result or generate an error message indicating that the filter is invalid and cannot be applied to the user search. Alternatively, the filter error could be handled appropriately and display an informational message instead of returning all users.

Actual Result:
The query returns all existing users in the database, which is not the expected behavior.

Provide error handling instead of panicking

Currently most of the domain logic uses unwrap for Result instances.
Instead we must propagate errors up by encouraging the use of the ? operator
and implementing Error enums based on domain logic.

The Repository trait uses an associate type to allow implementations
specifying a particular type for errors. We could use this_error crate to have
enums that we could then use on Repositories.

For instance:

UserError ->
    at: Repository -> UserError::NotFound, UserError::RepositoryError
    at: Service -> UserError::EmailTaken, UserError::WeakPassword
    at: GraphQL Interface

Case-sensitive validations for the existing username and email address

I think it would be good to be able to put the user name in upper or lower case, but without another one with the same name.

At the moment you can create a user in this way:

  • "michael"
  • "Michael"
  • "michaEL".

And they would be for completely different users.

What I mean is that the user name would appear as an example:

  • "Michael"

but without being able to create another user with the same characters

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.