├── .github
├── FUNDING.yml
├── Secrets Sync Action.yml
├── workflows
│ └── docker-image.yml
├── ISSUE_TEMPLATE
│ ├── feature_request.md
│ └── bug_report.md
└── header.svg
├── schemas
├── __init__.py
└── schemas.py
├── models
├── __init__.py
└── models.py
├── core
├── items
│ ├── __init__.py
│ ├── get_item.py
│ ├── add_item.py
│ └── delete_item.py
├── users
│ ├── __init__.py
│ ├── get_user.py
│ ├── login.py
│ └── register.py
└── cart
│ ├── __init__.py
│ ├── delete_cart_item.py
│ ├── add_to_cart.py
│ └── payment.py
├── data
├── __init__.py
├── database.py
└── alembic.ini
├── api
├── __init__.py
└── crud.py
├── docker-compose.yaml
├── Dockerfile
├── templates
└── index.html
├── requirements.txt
├── LICENSE
├── main.py
├── static
└── style.css
├── .dockerignore
├── .gitignore
└── README.md
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | custom: ["https://paypal.me/yassertahiri"]
--------------------------------------------------------------------------------
/schemas/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | from pydantic import BaseModel
--------------------------------------------------------------------------------
/.github/Secrets Sync Action.yml:
--------------------------------------------------------------------------------
1 | - name: Secrets Sync Action
2 | uses: jpoehnelt/secrets-sync-action@v1.4.1
--------------------------------------------------------------------------------
/models/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | from sqlalchemy import Column, Integer, String
3 | from data.database import Base
--------------------------------------------------------------------------------
/core/items/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | from sqlalchemy.orm import Session
3 | from fastapi import APIRouter, Depends, HTTPException
4 | from data import database
--------------------------------------------------------------------------------
/core/users/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | from sqlalchemy.orm import Session
3 | from fastapi import APIRouter, Depends, HTTPException
4 | from data import database
--------------------------------------------------------------------------------
/data/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | from sqlalchemy import create_engine
3 | from sqlalchemy.ext.declarative import declarative_base
4 | from sqlalchemy.orm import sessionmaker
--------------------------------------------------------------------------------
/core/cart/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | from sqlalchemy.orm import Session
3 | from fastapi import APIRouter, Depends, HTTPException
4 | from data import database
5 | from schemas import schemas
6 | from api import crud
7 | from data.database import get_db
8 |
--------------------------------------------------------------------------------
/api/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | from sqlalchemy.orm import Session
3 | from models import models
4 | from schemas import schemas
5 | import bcrypt
6 | import requests
7 | from requests.auth import HTTPBasicAuth
8 | import json
9 | from datetime import datetime
10 | import base64
--------------------------------------------------------------------------------
/docker-compose.yaml:
--------------------------------------------------------------------------------
1 | version: "3.8"
2 |
3 | services:
4 | web:
5 | build: ./DogeAPI
6 | command: uvicorn app.main:app --reload --workers 1 --host 0.0.0.0 --port 8000
7 | volumes:
8 | - ./DogeAPI:/usr/src/app
9 | ports:
10 | - 8004:8000
11 | environment:
12 | - ENVIRONMENT=dev
13 | - TESTING=0
--------------------------------------------------------------------------------
/.github/workflows/docker-image.yml:
--------------------------------------------------------------------------------
1 | name: Docker Image CI
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 | pull_request:
7 | branches: [ main ]
8 |
9 | jobs:
10 |
11 | build:
12 |
13 | runs-on: ubuntu-latest
14 |
15 | steps:
16 | - uses: actions/checkout@v2
17 | - name: Build the Docker image
18 | run: docker build . --file Dockerfile --tag my-image-name:$(date +%s)
19 |
--------------------------------------------------------------------------------
/data/database.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | from sqlalchemy import create_engine
3 | from sqlalchemy.ext.declarative import declarative_base
4 | from sqlalchemy.orm import sessionmaker
5 |
6 | SQLALCHEMY_DATABASE_URL = 'sqlite:///apollo.db'
7 | engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={
8 | "check_same_thread": False})
9 |
10 | SessionLocal = sessionmaker(bind=engine, autocommit=False, autoflush=False)
11 | Base = declarative_base()
12 |
13 |
14 | def get_db():
15 | db = SessionLocal()
16 | try:
17 | yield db
18 | finally:
19 | db.close()
20 |
--------------------------------------------------------------------------------
/core/users/get_user.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | from sqlalchemy.orm import Session
3 | from fastapi import APIRouter, Depends
4 | from data import database
5 |
6 | # import locale files
7 | from schemas import schemas
8 | from api import crud
9 | from data.database import get_db
10 |
11 | router = APIRouter(
12 | tags=["Users"],
13 | prefix="/user"
14 | )
15 | get_db = database.get_db
16 |
17 | # get user by username API
18 |
19 |
20 | @router.get("/get_user/{username}", response_model=schemas.UserInfo)
21 | def get_user(username, db: Session = Depends(get_db)):
22 | db_user = crud.get_user_by_username(db, username=username)
23 | return db_user
24 |
--------------------------------------------------------------------------------
/data/alembic.ini:
--------------------------------------------------------------------------------
1 | # initial file for apollo.db
2 |
3 | [loggers]
4 | keys = root,sqlalchemy,alembic
5 |
6 | [handlers]
7 | keys = console
8 |
9 | [formatters]
10 | keys = generic
11 |
12 | [logger_root]
13 | level = WARN
14 | handlers = console
15 | qualname =
16 |
17 | [logger_sqlalchemy]
18 | level = WARN
19 | handlers =
20 | qualname = sqlalchemy.engine
21 |
22 | [logger_alembic]
23 | level = INFO
24 | handlers =
25 | qualname = alembic
26 |
27 | [handler_console]
28 | class = StreamHandler
29 | args = (sys.stderr,)
30 | level = NOTSET
31 | formatter = generic
32 |
33 | [formatter_generic]
34 | format = %(levelname)-5.5s [%(name)s] %(message)s
35 | datefmt = %H:%M:%S
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ubuntu:latest
2 | FROM tiangolo/uvicorn-gunicorn-fastapi:python3.8
3 | RUN apt update && apt upgrade -y
4 |
5 | RUN apt install -y -q build-essential python3-pip python3-dev
6 | RUN pip3 install -U pip setuptools wheel
7 | RUN pip3 install gunicorn uvloop httptools
8 |
9 | COPY requirements.txt /app/requirements.txt
10 | RUN pip3 install -r /app/requirements.txt
11 |
12 | COPY ./ /app
13 |
14 | ENV ACCESS_LOG=${ACCESS_LOG:-/proc/1/fd/1}
15 | ENV ERROR_LOG=${ERROR_LOG:-/proc/1/fd/2}
16 |
17 | ENTRYPOINT /usr/local/bin/gunicorn \
18 | -b 0.0.0.0:80 \
19 | -w 4 \
20 | -k uvicorn.workers.UvicornWorker main:app \
21 | --chdir /app \
22 | --access-logfile "$ACCESS_LOG" \
23 | --error-logfile "$ERROR_LOG"
--------------------------------------------------------------------------------
/core/items/get_item.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | from sqlalchemy.orm import Session
3 | from fastapi import APIRouter, Depends, HTTPException
4 | from data import database
5 |
6 | # import locale files
7 | from schemas import schemas
8 | from api import crud
9 | from data.database import get_db
10 |
11 | router = APIRouter(
12 | tags=["Items"],
13 | prefix="/item"
14 | )
15 | get_db = database.get_db
16 |
17 | # get item by id API
18 |
19 |
20 | @router.get("/get_item/{id}", response_model=schemas.ItemAInfo)
21 | def get_item(id, db: Session = Depends(get_db)):
22 | db_item = crud.get_item_by_id(db, id=id)
23 | if db_item is None:
24 | raise HTTPException(status_code=400, detail="No item found")
25 | return db_item
26 |
--------------------------------------------------------------------------------
/core/items/add_item.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | from sqlalchemy.orm import Session
3 | from fastapi import APIRouter, Depends, HTTPException
4 | from data import database
5 |
6 | # import locale files
7 | from schemas import schemas
8 | from api import crud
9 | from data.database import get_db
10 |
11 | router = APIRouter(
12 | tags=["Items"],
13 | prefix="/item"
14 | )
15 | get_db = database.get_db
16 |
17 |
18 | # add items to DB API
19 |
20 |
21 | @router.post("/add_item", response_model=schemas.ItemInfo)
22 | def add_item(item: schemas.ItemInfo, db: Session = Depends(get_db)):
23 | db_item = crud.add_table(db=db, item=item)
24 | if db_item:
25 | raise HTTPException(status_code=200, detail="item registered")
26 | return {"Item": "Not Foundfound"}
27 |
--------------------------------------------------------------------------------
/core/users/login.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | from sqlalchemy.orm import Session
3 | from fastapi import APIRouter, Depends, HTTPException
4 | from data import database
5 |
6 | # import locale files
7 | from schemas import schemas
8 | from api import crud
9 | from data.database import get_db
10 |
11 | router = APIRouter(
12 | tags=["Users"],
13 | prefix="/user"
14 | )
15 | get_db = database.get_db
16 |
17 |
18 | # login API
19 |
20 |
21 | @router.post("/login")
22 | def login_user(user: schemas.UserLogin, db: Session = Depends(get_db)):
23 | db_user = crud.get_Login(
24 | db, username=user.username, password=user.password)
25 | if db_user == False:
26 | raise HTTPException(status_code=400, detail="Wrong username or password")
27 | return {"message": "User found"}
28 |
--------------------------------------------------------------------------------
/core/users/register.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | from sqlalchemy.orm import Session
3 | from fastapi import APIRouter, Depends, HTTPException
4 | from data import database
5 |
6 | # import locale files
7 | from schemas import schemas
8 | from api import crud
9 | from data.database import get_db
10 |
11 | router = APIRouter(
12 | tags=["Users"],
13 | prefix="/user"
14 | )
15 | get_db = database.get_db
16 |
17 | # register API
18 |
19 |
20 | @router.post("/register", response_model=schemas.UserInfo)
21 | def create_user(user: schemas.UserCreate, db: Session = Depends(get_db)):
22 | db_user = crud.get_user_by_username(db, username=user.username)
23 | if db_user:
24 | raise HTTPException(
25 | status_code=400, detail="Username already registered")
26 | return crud.create_user(db=db, user=user)
27 |
--------------------------------------------------------------------------------
/core/items/delete_item.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | from sqlalchemy.orm import Session
3 | from fastapi import APIRouter, Depends, HTTPException
4 | from data import database
5 |
6 | # import locale files
7 | from schemas import schemas
8 | from api import crud
9 | from data.database import get_db
10 |
11 | router = APIRouter(
12 | tags=["Items"],
13 | prefix="/item"
14 | )
15 | get_db = database.get_db
16 |
17 | # delete item by id API
18 |
19 |
20 | @router.delete("/del_item/{id}", response_model=schemas.ItemAInfo)
21 | def del_user(id, db: Session = Depends(get_db)):
22 | db_item = crud.delete_item_by_id(db, id=id)
23 | if db_item:
24 | raise HTTPException(status_code=200, detail="Item found to delete")
25 | else:
26 | raise HTTPException(status_code=400, detail="Item Not found to delete")
27 | return
28 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 |
16 | 1. Go to '...'
17 | 2. Click on '....'
18 | 3. Scroll down to '....'
19 | 4. See error
20 |
21 | **Expected behavior**
22 | A clear and concise description of what you expected to happen.
23 |
24 | **Screenshots**
25 | If applicable, add screenshots to help explain your problem.
26 |
27 | **Desktop (please complete the following information):**
28 |
29 | - OS: [e.g. Ubuntu]
30 | - Browser [e.g. chrome, safari]
31 | - Version [e.g. 22]
32 |
33 | **Additional context**
34 | Add any other context about the problem here.
35 |
--------------------------------------------------------------------------------
/core/cart/delete_cart_item.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | from sqlalchemy.orm import Session
3 | from fastapi import APIRouter, Depends, HTTPException
4 | from data import database
5 |
6 | # import locale files
7 | from schemas import schemas
8 | from api import crud
9 | from data.database import get_db
10 |
11 | # Create the Payment Router
12 | router = APIRouter(
13 | tags=["Payment"],
14 | prefix="/cart"
15 | )
16 | get_db = database.get_db
17 |
18 | # delete items in the cart by id API
19 | @router.delete("/delete_cart_item/{id}", response_model=schemas.CartItemAInfo)
20 | def del_user(id, db: Session = Depends(get_db)):
21 | db_item = crud.delete_cart_item_by_id(db, id=id)
22 | if db_item:
23 | raise HTTPException(status_code=200, detail="Item deleted")
24 | else:
25 | raise HTTPException(status_code=400, detail="Item Not found!")
26 | return
27 |
--------------------------------------------------------------------------------
/core/cart/add_to_cart.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | from sqlalchemy.orm import Session
3 | from fastapi import APIRouter, Depends, HTTPException
4 | from data import database
5 |
6 | # import locale files
7 | from schemas import schemas
8 | from api import crud
9 | from data.database import get_db
10 |
11 | # Create the Payment Router
12 | router = APIRouter(
13 | tags=["Payment"],
14 | prefix="/cart"
15 | )
16 | get_db = database.get_db
17 |
18 | # add to cart by username and the items to be added API
19 | @router.post("/add_to_cart/{username}", response_model=schemas.CartOwnerInfo)
20 | def add_item(username, items: schemas.CartInfo, db: Session = Depends(get_db)):
21 | db_cart = crud.add_to_cart(db=db, username=username, items=items)
22 | if db_cart:
23 | raise HTTPException(status_code=200, detail="Registered to The Cart")
24 | return {"Cart": "Item Not Registered to the Cart!"}
25 |
--------------------------------------------------------------------------------
/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 | Apollo-Auth
14 |
15 |
16 |
17 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/core/cart/payment.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | from sqlalchemy.orm import Session
3 | from fastapi import APIRouter, Depends, HTTPException
4 | from data import database
5 |
6 | # import locale files
7 | from schemas import schemas
8 | from api import crud
9 | from data.database import get_db
10 |
11 | # Create the Payment Router
12 | router = APIRouter(
13 | tags=["Payment"],
14 | prefix="/cart"
15 | )
16 | get_db = database.get_db
17 |
18 | # payment API
19 | @router.post("/payment")
20 | def add_item(userphone: schemas.UserPayment, db: Session = Depends(get_db)):
21 | user_payment = crud.payment(
22 | db=db, phone_number=userphone.phonenumber, total=userphone.total)
23 | if user_payment:
24 | raise HTTPException(status_code=200, detail="payment Started")
25 | return
26 |
27 | # Callback API
28 | @router.post("/callback")
29 | def money_callback(db: Session = Depends(get_db)):
30 | return {'success': "Payment was made successfully"}
31 |
--------------------------------------------------------------------------------
/models/models.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | from sqlalchemy import Column, Integer, String
3 | from data.database import Base
4 |
5 | # User Database Model
6 |
7 |
8 | class UserInfo(Base):
9 | __tablename__ = "user_info"
10 |
11 | id = Column(Integer, primary_key=True, index=True)
12 | username = Column(String, unique=True)
13 | password = Column(String)
14 | fullname = Column(String, unique=True)
15 |
16 | # Items Database Model
17 |
18 |
19 | class ItemInfo(Base):
20 | __tablename__ = "item_info"
21 |
22 | id = Column(Integer, primary_key=True, index=True)
23 | itemname = Column(String, unique=True)
24 | itemprice = Column(Integer)
25 |
26 |
27 | # Cart Database Model
28 |
29 |
30 | class CartInfo(Base):
31 | __tablename__ = "cart_info"
32 |
33 | id = Column(Integer, primary_key=True, index=True)
34 | ownername = Column(Integer, unique=True)
35 | itemname = Column(String, unique=True)
36 | itemprice = Column(Integer)
37 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | aiofiles==0.7.0
2 | asgiref==3.4.1
3 | astroid==2.6.2
4 | atomicwrites==1.4.0
5 | attrs==21.2.0
6 | autopep8==1.5.7
7 | backports.entry-points-selectable==1.1.0
8 | bcrypt==3.2.0
9 | certifi==2021.5.30
10 | cffi==1.14.6
11 | charset-normalizer==2.0.1
12 | click==8.0.1
13 | colorama==0.4.4
14 | distlib==0.3.2
15 | ecdsa==0.17.0
16 | fastapi==0.66.0
17 | filelock==3.0.12
18 | greenlet==1.1.0
19 | h11==0.12.0
20 | idna==3.2
21 | iniconfig==1.1.1
22 | isort==5.9.2
23 | Jinja2==3.0.1
24 | lazy-object-proxy==1.6.0
25 | MarkupSafe==2.0.1
26 | mccabe==0.6.1
27 | packaging==21.0
28 | passlib==1.7.4
29 | platformdirs==2.0.2
30 | pluggy==0.13.1
31 | py==1.10.0
32 | py-cpuinfo==8.0.0
33 | pyasn1==0.4.8
34 | pycodestyle==2.7.0
35 | pycparser==2.20
36 | pydantic==1.8.2
37 | pylint==2.9.3
38 | pyparsing==2.4.7
39 | pytest==6.2.4
40 | pytest-benchmark==3.4.1
41 | python-jose==3.3.0
42 | requests==2.26.0
43 | rsa==4.7.2
44 | six==1.16.0
45 | SQLAlchemy==1.4.20
46 | starlette==0.14.2
47 | toml==0.10.2
48 | tox==3.24.0
49 | typing-extensions==3.10.0.0
50 | urllib3==1.26.6
51 | uvicorn==0.14.0
52 | virtualenv==20.6.0
53 | wrapt==1.12.1
54 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Yasser Tahiri
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/schemas/schemas.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | from pydantic import BaseModel
3 |
4 | # base schema for user data
5 |
6 |
7 | class UserInfoBase(BaseModel):
8 | username: str
9 | fullname: str
10 |
11 | # schema for user creation(registration)
12 |
13 |
14 | class UserCreate(UserInfoBase):
15 | password: str
16 |
17 | # inherits from user data schema
18 |
19 |
20 | class UserInfo(UserInfoBase):
21 | id: int
22 |
23 | class Config:
24 | orm_mode = True
25 |
26 | # base schema for user login
27 |
28 |
29 | class UserLogin(BaseModel):
30 | username: str
31 | password: str
32 |
33 | # base schema for items
34 |
35 |
36 | class ItemInfo(BaseModel):
37 | itemname: str
38 | itemprice: int
39 |
40 | # inherits from item data schema used for getting item by id
41 |
42 |
43 | class ItemAInfo(ItemInfo):
44 | id: int
45 |
46 | class Config:
47 | orm_mode = True
48 |
49 | # base schema for relating a cart to it's user
50 |
51 |
52 | class CartOwnerInfo(BaseModel):
53 | username: str
54 |
55 | # base schema for adding items to cart
56 |
57 |
58 | class CartInfo(BaseModel):
59 | itemname: str
60 | itemprice: int
61 |
62 | # base schema for getting items in the cart by id
63 |
64 |
65 | class CartItemAInfo(CartInfo):
66 | id: int
67 |
68 | class Config:
69 | orm_mode = True
70 |
71 | # base schema for the payment api
72 |
73 |
74 | class UserPayment(BaseModel):
75 | phonenumber: int
76 | total: int
77 |
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 |
3 | from fastapi import FastAPI, Request
4 | from starlette.responses import HTMLResponse
5 | from fastapi.staticfiles import StaticFiles
6 | from fastapi.templating import Jinja2Templates
7 |
8 | # import locale files
9 | from models import models
10 | from data.database import engine
11 |
12 | # import router files
13 | from core.cart import add_to_cart, delete_cart_item, payment
14 | from core.items import add_item, delete_item, get_item
15 | from core.users import login, register, get_user
16 |
17 | # Create the database tables
18 | models.Base.metadata.create_all(bind=engine)
19 |
20 | # Create the instance
21 | app = FastAPI(
22 | title="Apollo - Auth",
23 | description="A basic Application with multiple functionality",
24 | version="1.0.0",
25 | )
26 |
27 | app.mount("/static", StaticFiles(directory="static"), name="static")
28 | templates = Jinja2Templates(directory="templates")
29 |
30 | # includes all users routes
31 | app.include_router(login.router)
32 | app.include_router(register.router)
33 | app.include_router(get_user.router)
34 |
35 | # includes all items routes
36 | app.include_router(add_item.router)
37 | app.include_router(get_item.router)
38 | app.include_router(delete_item.router)
39 |
40 | # includes all cart
41 | app.include_router(add_to_cart.router)
42 | app.include_router(payment.router)
43 | app.include_router(delete_cart_item.router)
44 |
45 | # By default FastAPI return the response using JSONResponse,
46 | # but we will Custom our Response using the HTMLResponse
47 | @app.get("/", response_class=HTMLResponse)
48 | async def index(request: Request):
49 | return templates.TemplateResponse("index.html", {"request": request})
50 |
--------------------------------------------------------------------------------
/.github/header.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 | APOLLO
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/static/style.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
6 | html,
7 | body {
8 | box-sizing: border-box;
9 | height: 100%;
10 | width: 100%;
11 | }
12 |
13 | body {
14 | background: #FFF;
15 | font-family: 'fantasy', emoji;
16 | font-weight: 400;
17 | }
18 |
19 | .buttons {
20 | display: flex;
21 | flex-direction: row;
22 | flex-wrap: wrap;
23 | justify-content: center;
24 | text-align: center;
25 | width: 100%;
26 | height: 100%;
27 | margin: 0 auto;
28 | /* padding: 2em 0em; */
29 | }
30 |
31 | .container {
32 | align-items: center;
33 | display: flex;
34 | flex-direction: column;
35 | justify-content: center;
36 | text-align: center;
37 | background-color: #FFF;
38 | padding: 40px 0px;
39 | width: 240px;
40 | }
41 |
42 | h1 {
43 | text-align: left;
44 | color: #444;
45 | letter-spacing: 0.05em;
46 | margin: 0 0 0.4em;
47 | font-size: 1em;
48 | }
49 |
50 | p {
51 | text-align: left;
52 | color: #444;
53 | letter-spacing: 0.05em;
54 | font-size: 0.8em;
55 | margin: 0 0 2em;
56 | }
57 |
58 |
59 | .btn {
60 | letter-spacing: 0.1em;
61 | cursor: pointer;
62 | font-size: 14px;
63 | font-weight: 400;
64 | line-height: 45px;
65 | max-width: 160px;
66 | position: relative;
67 | text-decoration: none;
68 | text-transform: uppercase;
69 | width: 100%;
70 | }
71 |
72 | .btn:hover {
73 | text-decoration: none;
74 | }
75 |
76 | /*btn_background*/
77 | .effect04 {
78 | --uismLinkDisplay: var(--smLinkDisplay, inline-flex);
79 | display: var(--uismLinkDisplay);
80 | color: #000;
81 | outline: solid 2px #000;
82 | position: relative;
83 | transition-duration: 0.4s;
84 | overflow: hidden;
85 | }
86 |
87 | .effect04::before,
88 | .effect04 span {
89 | margin: 0 auto;
90 | transition-timing-function: cubic-bezier(0.86, 0, 0.07, 1);
91 | transition-duration: 0.4s;
92 | }
93 |
94 | .effect04:hover {
95 |
96 | background-color: #000;
97 | }
98 |
99 | .effect04:hover span {
100 | -webkit-transform: translateY(-400%) scale(-0.1, 20);
101 | transform: translateY(-400%) scale(-0.1, 20);
102 | }
103 |
104 |
105 | .effect04::before {
106 | content: attr(data-sm-link-text);
107 | color: #FFF;
108 | position: absolute;
109 | left: 0;
110 | right: 0;
111 | margin: auto;
112 | -webkit-transform: translateY(500%) scale(-0.1, 20);
113 | transform: translateY(500%) scale(-0.1, 20);
114 | }
115 |
116 | .effect04:hover::before {
117 | letter-spacing: 0.05em;
118 | -webkit-transform: translateY(0) scale(1, 1);
119 | transform: translateY(0) scale(1, 1);
120 | }
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | share/python-wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 | MANIFEST
28 |
29 | # PyInstaller
30 | # Usually these files are written by a python script from a template
31 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
32 | *.manifest
33 | *.spec
34 |
35 | # Installer logs
36 | pip-log.txt
37 | pip-delete-this-directory.txt
38 |
39 | # Unit test / coverage reports
40 | htmlcov/
41 | .tox/
42 | .nox/
43 | .coverage
44 | .coverage.*
45 | .cache
46 | nosetests.xml
47 | coverage.xml
48 | *.cover
49 | *.py,cover
50 | .hypothesis/
51 | .pytest_cache/
52 | cover/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 | apollo.db
64 |
65 | # Flask stuff:
66 | instance/
67 | .webassets-cache
68 |
69 | # Scrapy stuff:
70 | .scrapy
71 |
72 | # Sphinx documentation
73 | docs/_build/
74 |
75 | # PyBuilder
76 | .pybuilder/
77 | target/
78 |
79 | # Jupyter Notebook
80 | .ipynb_checkpoints
81 |
82 | # IPython
83 | profile_default/
84 | ipython_config.py
85 |
86 | # pyenv
87 | # For a library or package, you might want to ignore these files since the code is
88 | # intended to run in multiple environments; otherwise, check them in:
89 | # .python-version
90 |
91 | # pipenv
92 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
93 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
94 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
95 | # install all needed dependencies.
96 | #Pipfile.lock
97 |
98 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
99 | __pypackages__/
100 |
101 | # Celery stuff
102 | celerybeat-schedule
103 | celerybeat.pid
104 |
105 | # SageMath parsed files
106 | *.sage.py
107 |
108 | # Environments
109 | .env
110 | .venv
111 | env/
112 | venv/
113 | ENV/
114 | env.bak/
115 | venv.bak/
116 |
117 | # Spyder project settings
118 | .spyderproject
119 | .spyproject
120 |
121 | # Rope project settings
122 | .ropeproject
123 |
124 | # mkdocs documentation
125 | /site
126 |
127 | # mypy
128 | .mypy_cache/
129 | .dmypy.json
130 | dmypy.json
131 |
132 | # Pyre type checker
133 | .pyre/
134 |
135 | # pytype static type analyzer
136 | .pytype/
137 |
138 | # Cython debug symbols
139 | cython_debug/
140 |
141 | .DS_Store
142 | .env
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | share/python-wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 | MANIFEST
28 |
29 | # PyInstaller
30 | # Usually these files are written by a python script from a template
31 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
32 | *.manifest
33 | *.spec
34 |
35 | # Installer logs
36 | pip-log.txt
37 | pip-delete-this-directory.txt
38 |
39 | # Unit test / coverage reports
40 | htmlcov/
41 | .tox/
42 | .nox/
43 | .coverage
44 | .coverage.*
45 | .cache
46 | nosetests.xml
47 | coverage.xml
48 | *.cover
49 | *.py,cover
50 | .hypothesis/
51 | .pytest_cache/
52 | cover/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 | apollo.db
64 |
65 | # Flask stuff:
66 | instance/
67 | .webassets-cache
68 |
69 | # Scrapy stuff:
70 | .scrapy
71 |
72 | # Sphinx documentation
73 | docs/_build/
74 |
75 | # PyBuilder
76 | .pybuilder/
77 | target/
78 |
79 | # Jupyter Notebook
80 | .ipynb_checkpoints
81 |
82 | # IPython
83 | profile_default/
84 | ipython_config.py
85 |
86 | # pyenv
87 | # For a library or package, you might want to ignore these files since the code is
88 | # intended to run in multiple environments; otherwise, check them in:
89 | # .python-version
90 |
91 | # pipenv
92 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
93 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
94 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
95 | # install all needed dependencies.
96 | #Pipfile.lock
97 |
98 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
99 | __pypackages__/
100 |
101 | # Celery stuff
102 | celerybeat-schedule
103 | celerybeat.pid
104 |
105 | # SageMath parsed files
106 | *.sage.py
107 |
108 | # Environments
109 | .env
110 | .venv
111 | env/
112 | venv/
113 | ENV/
114 | env.bak/
115 | venv.bak/
116 |
117 | # Spyder project settings
118 | .spyderproject
119 | .spyproject
120 |
121 | # Rope project settings
122 | .ropeproject
123 |
124 | # mkdocs documentation
125 | /site
126 |
127 | # mypy
128 | .mypy_cache/
129 | .dmypy.json
130 | dmypy.json
131 |
132 | # Pyre type checker
133 | .pyre/
134 |
135 | # pytype static type analyzer
136 | .pytype/
137 |
138 | # Cython debug symbols
139 | cython_debug/
140 |
141 | .DS_Store
142 | .env
143 | .idea/
144 | .vim/
145 | token_examples.md
146 |
--------------------------------------------------------------------------------
/api/crud.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | from sqlalchemy.orm import Session
3 | from models import models
4 | from schemas import schemas
5 | import bcrypt
6 | import requests
7 | from requests.auth import HTTPBasicAuth
8 | import json
9 | from datetime import datetime
10 | import base64
11 |
12 |
13 | # Get user by username function
14 |
15 |
16 | def get_user_by_username(db: Session, username: str):
17 | return db.query(models.UserInfo).filter(models.UserInfo.username == username).first()
18 |
19 | # User registration function
20 |
21 |
22 | def create_user(db: Session, user: schemas.UserCreate):
23 | hashed_password = bcrypt.hashpw(
24 | user.password.encode('utf-8'), bcrypt.gensalt())
25 | db_user = models.UserInfo(username=user.username,
26 | password=hashed_password, fullname=user.fullname)
27 | db.add(db_user)
28 | db.commit()
29 | db.refresh(db_user)
30 | return db_user
31 |
32 | # Login Function
33 |
34 |
35 | def get_Login(db: Session, username: str, password: str):
36 | db_user = db.query(models.UserInfo).filter(
37 | models.UserInfo.username == username).first()
38 | print(username, password)
39 | passw = bcrypt.checkpw(password.encode('utf-8'), db_user.password)
40 | return passw
41 |
42 | # Get item by id function
43 |
44 |
45 | def get_item_by_id(db: Session, id: int):
46 | return db.query(models.ItemInfo).filter(models.ItemInfo.id == id).first()
47 |
48 | # Add items to DB function
49 |
50 |
51 | def add_table(db: Session, item: schemas.ItemInfo):
52 | db_item = models.ItemInfo(itemname=item.itemname, itemprice=item.itemprice)
53 | db.add(db_item)
54 | db.commit()
55 | db.refresh(db_item)
56 | return db_item
57 |
58 | # Delete item from DB by id function
59 |
60 |
61 | def delete_item_by_id(db: Session, id: int):
62 | delitem = db.query(models.ItemInfo).filter(
63 | models.ItemInfo.id == id).first()
64 | if delitem is None:
65 | return
66 | db.delete(delitem)
67 | db.commit()
68 | return delitem
69 |
70 | # Add to cart function
71 |
72 |
73 | def add_to_cart(db: Session, username: str, items: models.CartInfo):
74 | user = db.query(models.UserInfo).filter(
75 | models.UserInfo.username == username).first()
76 | db_cart = models.CartInfo(
77 | ownername=user.id, itemname=items.itemname, itemprice=items.itemprice)
78 | db.add(db_cart)
79 | db.commit()
80 | db.refresh(db_cart)
81 | return db_cart
82 |
83 | # Delete item in the cart by id
84 |
85 |
86 | def delete_cart_item_by_id(db: Session, id: int):
87 | delitem = db.query(models.CartInfo).filter(
88 | models.CartInfo.id == id).first()
89 | if delitem is None:
90 | return
91 | db.delete(delitem)
92 | db.commit()
93 | return delitem
94 |
95 | # money processing function(Not Complete Yet)
96 |
97 |
98 | def payment(db: Session, phone_number: int, total: int):
99 | consumer_key = 'consumer_key'
100 | consumer_secret = 'consumer_secret'
101 | api_URL = 'https://api-m.sandbox.paypal.com/v1/payments'
102 |
103 | req = requests.get(api_URL, auth=HTTPBasicAuth(
104 | consumer_key, consumer_secret))
105 | money_access_token = json.loads(req.text)
106 | validated_money_access_token = money_access_token['access_token']
107 |
108 | time = datetime.now().strftime('%Y%m%d%H%M%S')
109 | Business_code = 'short_code' # replace with the business short code
110 | passkey = "pass_key"
111 | data_to_encode = Business_code + passkey + time
112 | online_password = base64.b64encode(data_to_encode.encode())
113 | decode_password = online_password.decode('utf-8')
114 |
115 | access_token = validated_money_access_token
116 | api_url = "https://api-m.sandbox.paypal.com/v1/payments/payment?count=10&start_index=0&sort_by=create_time&sort_order=desc"
117 | headers = {"Authorization": "Bearer %s" % access_token}
118 | request = {
119 | "BusinessShortCode": Business_code,
120 | "Password": decode_password,
121 | "Timestamp": time,
122 | "TransactionType": "CustomerPayBillOnline",
123 | "Amount": total,
124 | "PhoneNumber": phone_number,
125 | "CallBackURL": "https://127.0.0.1:8000/callback", # Money Callback
126 | "AccountReference": "User Payment",
127 | "TransactionDesc": "Testing stk push"
128 | }
129 | response = requests.post(api_url, json=request, headers=headers)
130 | return response.text
131 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # Apollo
4 |
5 | A basic Application with multiple functionalities built with FastAPI aim to help Users Buy New Items Provided by PaypalAPI to Complete the Payment and Check it.
6 |
7 | ## Getting Started
8 |
9 | Apollo provide a Basic API Compose :
10 |
11 |
12 | Users
13 |
14 | login : http://localhost:8000 user/login
15 | Register : http://localhost:8000/user/register
16 | Get User : http://localhost:8000/user/get_user/{username}
17 |
18 | Items
19 |
20 | Add Item : http://localhost:8000/item/add_item
21 | Get Item : http://localhost:8000/item/get_item/{id}
22 | Delete Item : http://localhost:8000/item/get_item/{id}
23 |
24 | Payment
25 |
26 | Add Item to Cart : http://localhost:8000/cart/add_to_cart/{username}
27 | Provide Item to Payments : http://localhost:8000/cart/payment
28 | Money Callback : http://localhost:8000/cart/callback
29 | Delete Cart Item : http://localhost:8000/cart/delete_cart_item/{id}
30 |
31 |
32 |
33 | > I pre-configured the Cruds with the payment process based on `PaypalAPI`, you can read the Official docs here [REST APIs / API Requests](https://developer.paypal.com/docs/api/reference/api-requests/)
34 |
35 | ### Prerequisites
36 |
37 | - Python 3.9.2 or higher
38 | - FastAPI
39 | - Docker
40 |
41 | ### Project setup
42 |
43 | ```sh
44 | # clone the repo
45 | $ git clone https://github.com/yezz123/Apollo.git
46 |
47 | # move to the project folder
48 | $ cd Apollo
49 | ```
50 |
51 | ### Creating virtual environment
52 |
53 | - Install `pipenv` a global python project `pip install pipenv`
54 | - Create a `virtual environment` for this project
55 |
56 | ```shell
57 | # creating pipenv environment for python 3
58 | $ pipenv --three
59 |
60 | # activating the pipenv environment
61 | $ pipenv shell
62 |
63 | # if you have multiple python 3 versions installed then
64 | $ pipenv install -d --python 3.8
65 |
66 | # install all dependencies (include -d for installing dev dependencies)
67 | $ pipenv install -d
68 | ```
69 |
70 | ### Running the Application
71 |
72 | - To run the [Main](main.py) we need to use [uvicorn](https://www.uvicorn.org/) a lightning-fast ASGI server implementation, using uvloop and httptools.
73 |
74 | ```sh
75 | # Running the application using uvicorn
76 | $ uvicorn main:app
77 |
78 | ## To run the Application under a reload enviromment use -- reload
79 | $ uvicorn main:app --reload
80 | ```
81 |
82 | - Here we can Switch Between using [SWAGGER UI](https://swagger.io/tools/swagger-ui/) or [Redoc](https://redocly.github.io/redoc/) to Play around the API.
83 |
84 | - You can Now Start using the Application, i use a simple Template for the `index` file to simply launch `/docs` :
85 |
86 | ### Configured Enviromment
87 |
88 | - To Provide a good work, i choose a `SQLite` Database using `SQLAlchemy`.
89 | - If you want to configure the Database with an other Provider like `MySQL` or `PostgreSQL` you can change the `Database_URL` here :
90 |
91 | - [Database.py](data/database.py) :
92 |
93 | ```py
94 | # here you need to insert the Connection URL.
95 | SQLALCHEMY_DATABASE_URL = 'sqlite:///apollo.db'
96 | ```
97 |
98 | - For Example
99 |
100 | ```py
101 | SQLALCHEMY_DATABASE_URL = 'mysql://username:password@server/apollo'
102 | ```
103 |
104 | ## Running the Docker Container
105 |
106 | - We have the Dockerfile created in above section. Now, we will use the Dockerfile to create the image of the FastAPI app and then start the FastAPI app container.
107 |
108 | ```sh
109 | $ docker build
110 | ```
111 |
112 | - list all the docker images and you can also see the image `apollo:latest` in the list.
113 |
114 | ```sh
115 | $ docker images
116 | ```
117 |
118 | - run the application at port 5000. The various options used are:
119 |
120 | > - `-p`: publish the container's port to the host port.
121 | > - `-d`: run the container in the background.
122 | > - `-i`: run the container in interactive mode.
123 | > - `-t`: to allocate pseudo-TTY.
124 | > - `--name`: name of the container
125 |
126 | ```sh
127 | $ docker container run -p 5000:5000 -dit --name Apollo apollo:latest
128 | ```
129 |
130 | - Check the status of the docker container
131 |
132 | ```sh
133 | $ docker container ps
134 | ```
135 |
136 | ## Preconfigured Packages
137 |
138 | Includes preconfigured packages to kick start Apollo API by just setting appropriate configuration.
139 |
140 | | Package | Usage |
141 | | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------- |
142 | | [uvicorn](https://www.uvicorn.org/) | a lightning-fast ASGI server implementation, using uvloop and httptools. |
143 | | [PaypalAPI](https://developer.paypal.com/docs/api/overview/) | exchange these credentials for an access token that authorizes your REST API calls. To test your web and mobile apps. |
144 | | [SQLAlchemy](https://www.sqlalchemy.org/) | is the Python SQL toolkit and Object Relational Mapper that gives application developers the full power and flexibility of SQL. |
145 | | [starlette](https://www.starlette.io/) | a lightweight ASGI framework/toolkit, which is ideal for building high performance asyncio services. |
146 |
147 | `yapf` packages for `linting and formatting`
148 |
149 | ## Contributing
150 |
151 | - Join the Apollo Creator and Contribute to the Project if you have any enhancement or add-ons to create a good and Secure Project, Help any User to Use it in a good and simple way.
152 |
153 | ## License
154 |
155 | This program is free software under MIT license. Please see the [LICENSE](LICENSE) file in our repository for the full text.
156 |
--------------------------------------------------------------------------------