Skip to content

Commit

Permalink
Merge pull request #3 from LionelMv/pre-dev
Browse files Browse the repository at this point in the history
Pre dev
  • Loading branch information
LionelMv authored Sep 25, 2024
2 parents bfa4b95 + 6cb0ad4 commit 0691b89
Show file tree
Hide file tree
Showing 22 changed files with 595 additions and 13 deletions.
22 changes: 22 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[run]
source =
project

omit =
*/migrations/*
*/tests/*
*/admin.py
*/apps.py
*/urls.py
manage.py

[report]
exclude_lines =
pragma: no cover
def __str__
def __repr__
pass
raise NotImplementedError

[html]
directory = htmlcov
83 changes: 83 additions & 0 deletions .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
name: CI/CD Pipeline

on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:
test:
runs-on: ubuntu-latest

services:
postgres:
image: postgres:latest
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: testdb
ports:
- 5432:5432
options: >-
--health-cmd="pg_isready -U postgres"
--health-interval=10s
--health-timeout=5s
--health-retries=5
steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.12'

- name: Install Pipenv
run: |
python -m pip install --upgrade pip
pip install pipenv
- name: Install dependencies
run: |
pipenv install --dev
- name: Set up environment variables
run: |
echo "SECRET_KEY=${{ secrets.SECRET_KEY }}" >> $GITHUB_ENV
echo "GOOGLE_CLIENT_ID=${{ secrets.GOOGLE_CLIENT_ID }}" >> $GITHUB_ENV
echo "GOOGLE_CLIENT_SECRET=${{ secrets.GOOGLE_CLIENT_SECRET }}" >> $GITHUB_ENV
echo "SMS_USERNAME=${{ secrets.SMS_USERNAME }}" >> $GITHUB_ENV
echo "SMS_API_KEY=${{ secrets.SMS_API_KEY }}" >> $GITHUB_ENV
- name: Set up Database
run: |
pipenv run python manage.py migrate
- name: Run Tests with coverage
run: |
pipenv run coverage run manage.py test
pipenv run coverage html
pipenv run coverage report
- name: Upload Coverage Report
if: success()
uses: actions/upload-artifact@v3
with:
name: coverage-report
path: htmlcov/

deploy:
runs-on: ubuntu-latest
needs: test
steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Deploy to your environment
# This is a placeholder. Configure your deployment steps here.
run: echo "Deploying application..."

7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
.env
.coverage
htmlcov/

# Pipenv
Pipfile.lock

project/views1.py
project/urls1.py
api/__pycache__/
project/__pycache__/
project/migrations/__pycache__/
project/tests/__pycache__/
project/utils/__pycache__/
4 changes: 4 additions & 0 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ django = "*"
python-decouple = "*"
psycopg = {extras = ["binary"], version = "*"}
djangorestframework = "*"
coverage = "*"
django-allauth = {extras = ["socialaccount"], version = "*"}
django-oauth-toolkit = "*"
africastalking = "*"

[dev-packages]

Expand Down
73 changes: 73 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Vitabu
This API provides a simple service for managing customers and their orders, implementing secure authentication using OpenID Connect (OIDC) and sending SMS notifications upon order creation. The application is built using Django and Django REST Framework (DRF) with PostgreSQL as the database, and leverages Africa’s Talking SMS gateway for real-time alerts.

## Key Features
1. **Customer Management:** Create, update, and view customers, including details such as name, email, and unique codes.

2. **Order Management:** Create and view orders linked to customers, with details such as item name, amount, and order timestamp.

3. **Authentication and Authorization:** Secure access to the API using OpenID Connect (OIDC) via django-allauth, enabling seamless integration with identity providers like Google for OAuth2-based authentication.

4. **SMS Notifications:** Upon successful order creation, the API sends an SMS notification to the customer's registered phone number using Africa’s Talking SMS gateway.
5. **Testing and CI/CD:** Includes comprehensive unit tests to ensure reliability, with continuous integration and deployment setups for automated testing and deployment.

## Technologies Used
- **Backend:** Python, Django, Django REST Framework
Database: PostgreSQL
- **Authentication:** OpenID Connect (OIDC) via django-allauth
- **SMS Alerts:** Africa’s Talking SMS gateway
- **CI/CD:** GitHub Actions

## Setup & Installation
1. Clone the repository.
2. Install pipenv:
- On Linux
```sh
sudo apt-get install pipenv
```
- On macOS or Windows
```sh
pip install pipenv
```
3. Setup project environment:
```sh
pipenv install
```
4. Activate the project environment:
```sh
pipenv shell
```
For more information about Pipenv, check: [Pipenv: A Guide to The New Python Packaging Tool - Real Pyhton](https://realpython.com/pipenv-guide/)

5. Copy the envsample file to the root folder with the name ```.env```.
Change settings and configurations on the ```.env``` file:
- Database settings: Used PostgreSQL for this project.
- All Auth settings: Google's client_id and client_secret.
- Africa's Talking Settings: username and api key

6. Make changes to your database:
```sh
python manage.py migrate
```
7. Usage:
```sh
cd Vitabu-api
python manage.py runserver
```
On your browser, run the following link: http://localhost:8000/accounts/login.
Tap on Google to sign in with Google to access the API.

## API Documentation
The documentation of the API created using Django Rest Framework (DRF) is on the file ```api.md```.

## Contributing
Want to make TradersIn better?
- Fork the project.
- Create a new branch to work on ```git checkout -b <feature_branch>```
- You can name the branch with the prefix ```feature_```
- Add your changes and push them to the branch: ```git push```
- Open a pull request


## Authors
Lionel Gicheru [LinkedIn](https://www.linkedin.com/in/lionelmwangi/)
82 changes: 82 additions & 0 deletions api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# API Documentation
### Customer Endpoints
1. List All Customers
- URL: /api/customers
- Method: GET
- Description: Retrieve a list of all customers.
- Response Example:
```sh
[
{
"id": 2,
"name": "Mwangi",
"email": "mvangicode@gmail.com",
"code": "CUST254",
"phone_number": "+25470...."
},
...
]
```

2. Retrieve, Update, or Delete a Specific Customer

- URL: api/customers/\<int:pk\>/
- Methods: GET, PUT, DELETE
- Description: Retrieve, update, or delete a specific customer by their primary key.
- Response Example (GET):
```sh
{
"id": 2,
"name": "Mwangi",
"email": "mvangicode@gmail.com",
"code": "CUST254",
"phone_number": "+25470...."
}
```

### Order Endpoints
3. List All Orders
- URL: /orders/
- Method: GET
- Description: Retrieve a list of all orders.
- Response Example:
```sh
[
{
"id": 2,
"item": "Book A",
"amount": "20.00",
"time": "2024-09-24T21:21:28.341126Z",
"customer": {
"id": 2,
"name": "Mwangi",
"email": "mvangicode@gmail.com",
"code": "CUST254",
"phone_number": "+25470..."
}
},
...
]
```

4. Retrieve, Update, or Delete a Specific Order

- URL: /orders/\<int:pk\>/
- Methods: GET, PUT, PATCH, DELETE
- Description: Retrieve, update, or delete a specific order by their primary key.
- Response Example (GET):
```sh
{
"id": 2,
"item": "Book A",
"amount": "20.00",
"time": "2024-09-24T21:21:28.341126Z",
"customer": {
"id": 2,
"name": "Mwangi",
"email": "mvangicode@gmail.com",
"code": "CUST254",
"phone_number": "+254705305054"
}
}
```
65 changes: 58 additions & 7 deletions api/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []
ALLOWED_HOSTS = ['localhost']


# Application definition
Expand All @@ -38,10 +38,20 @@
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'project',

# Third party apps
'rest_framework',
'project'

# Allauth
'django.contrib.sites',
'allauth',
'allauth.account',
'allauth.socialaccount',
'allauth.socialaccount.providers.google',

# OAuth toolkit
'oauth2_provider',
]

MIDDLEWARE = [
Expand All @@ -52,6 +62,9 @@
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',

# Allauth
'allauth.account.middleware.AccountMiddleware',
]

ROOT_URLCONF = 'api.urls'
Expand All @@ -67,6 +80,9 @@
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',

# allauth
'django.template.context_processors.request',
],
},
},
Expand All @@ -81,11 +97,11 @@
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': config("DB_NAME"),
'USER': config("DB_USER"),
'PASSWORD': config("DB_PASSWORD"),
'HOST': config("DB_HOST"),
'PORT': config("DB_PORT"),
'NAME': config("DB_NAME", default="testdb"),
'USER': config("DB_USER", default="postgres"),
'PASSWORD': config("DB_PASSWORD", default="postgres"),
'HOST': config("DB_HOST", default="localhost"),
'PORT': config("DB_PORT", default="5432"),
}
}

Expand Down Expand Up @@ -130,3 +146,38 @@
# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

# Allauth
AUTHENTICATION_BACKENDS = [
# Needed to login by username in Django admin, regardless of `allauth`
'django.contrib.auth.backends.ModelBackend',

# `allauth` specific authentication methods, such as login by email
'allauth.account.auth_backends.AuthenticationBackend',
]

# allauth
SITE_ID = 1

REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'oauth2_provider.contrib.rest_framework.OAuth2Authentication', # OAuth2 Auth
'rest_framework.authentication.SessionAuthentication', # Session Auth (for logged-in users via the web)
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated', # Restrict access to authenticated users
),
}

SOCIALACCOUNT_PROVIDERS = {
'google': {
'APP': {
'client_id': config("GOOGLE_CLIENT_ID"),
'secret': config("GOOGLE_CLIENT_SECRET"),
'key': ''
}
}
}

LOGIN_REDIRECT_URL = '/api/customers/'
LOGOUT_REDIRECT_URL = '/accounts/login/'
Loading

0 comments on commit 0691b89

Please sign in to comment.