-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from Esekyi/feature/recipe_forms
Feature/recipe forms
- Loading branch information
Showing
24 changed files
with
2,226 additions
and
49 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,29 @@ | ||
.venv/ | ||
__pycache__/ | ||
.env | ||
notice.txt | ||
|
||
# IDE and editor files | ||
.vscode/ | ||
.idea/ | ||
*.swp | ||
*.swo | ||
.DS_Store | ||
|
||
# Compiled Python files | ||
*.pyc | ||
*.pyo | ||
*.pyd | ||
# Temporary files | ||
*.bak | ||
*.tmp | ||
|
||
# Node.js | ||
node_modules/ | ||
npm-debug.log | ||
yarn-error.log | ||
yarn-debug.log | ||
.pnpm-debug.log | ||
|
||
# Operating system files | ||
Thumbs.db |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,65 @@ | ||
# SpiceShare - A recipe-sharing web app | ||
|
||
SpiceShare is a web application that allows users to share and discover recipes from around the world. | ||
|
||
## Features | ||
|
||
- User authentication | ||
- Recipe creation and sharing | ||
- Search and filter recipes | ||
- Favorite and save recipes (later updates) | ||
- User profiles | ||
|
||
## Prerequisites | ||
Before you begin, ensure you have met the following requirements: | ||
|
||
- Node.js (v14.x or later) | ||
- npm (v6.x or later) | ||
|
||
--- this is only used to build tailwind css | ||
|
||
## Installation | ||
|
||
To install SpiceShare, follow these steps: | ||
|
||
1. Clone the repository: | ||
``` | ||
https://github.com/Esekyi/SpiceShare.git | ||
cd spiceshare | ||
``` | ||
|
||
2. Install dependencies: | ||
python and flask | ||
``` | ||
python3 -m venv .venv | ||
python3 -m pip install -r requirements.txt | ||
``` | ||
Node for tailwind css build | ||
``` | ||
npm install | ||
# or | ||
yarn install | ||
``` | ||
|
||
|
||
|
||
|
||
## Contributing | ||
|
||
Contributions to SpiceShare are welcome! Please follow these steps: | ||
|
||
1. Fork the repository | ||
2. Create a new branch: `git checkout -b feature/your-feature-name` | ||
3. Make your changes and commit them: `git commit -m 'Add some feature'` | ||
4. Push to the branch: `git push origin feature/your-feature-name` | ||
5. Submit a pull request | ||
|
||
Please make sure to update tests as appropriate and adhere to the project's coding standards. | ||
|
||
## License | ||
|
||
[MIT License](LICENSE) | ||
|
||
## Contact | ||
|
||
If you have any questions or feedback, please open an issue on GitHub or contact the maintainer at [email protected]. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
from flask import Blueprint, render_template, request, flash, redirect, url_for, jsonify | ||
from flask_login import login_user, logout_user, login_required, current_user | ||
from werkzeug.security import check_password_hash | ||
from app.models.user import User | ||
from app import db | ||
|
||
"""Route for basic authentication""" | ||
|
||
auth_bp = Blueprint('auth', __name__) | ||
|
||
@auth_bp.route('/login', methods=['GET','POST']) | ||
def login(): | ||
"""Login authentication handler""" | ||
if request.method == 'POST': | ||
email = request.form["email"] | ||
password = request.form["password"] | ||
user = User.query.filter_by(email=email).first() | ||
|
||
if user and check_password_hash(user.password_hash, password): | ||
login_user(user) | ||
return jsonify({"success": "you're logged in"}) | ||
|
||
flash('Invalid Credentials', 'warning') | ||
|
||
return render_template('login.html') | ||
|
||
@auth_bp.route('/logout') | ||
@login_required | ||
def logout(): | ||
"""logout handler""" | ||
logout_user() | ||
return redirect(url_for('auth.login')) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,107 @@ | ||
from flask import Blueprint, jsonify, request | ||
"""User services routes""" | ||
from flask import Blueprint, jsonify, request, flash, redirect, url_for, render_template | ||
from app import db | ||
from app.services.user_services import get_all_users | ||
from app.services.user_services import create_user | ||
from app.services.user_services import get_all_users, delete_user, get_user_by_id, update_user, create_user, get_user_by_email | ||
from flask_login import login_required, current_user | ||
|
||
# user routes blueprint | ||
bp = Blueprint('user_routes', __name__) | ||
|
||
@bp.route('/users', methods=['GET']) | ||
def list_users(): | ||
users = get_all_users() | ||
return jsonify([user.username for user in users]) | ||
"""get all users in db""" | ||
users = get_all_users() | ||
for user in users: | ||
return jsonify({ | ||
"id": user.id, | ||
"name": user.first_name + ' ' + user.last_name, | ||
"email": user.email, | ||
"password": user.password_hash | ||
}) | ||
|
||
|
||
@bp.route('/users', methods=['POST']) | ||
def add_user(): | ||
data = request.get_json() | ||
user = create_user(data['username'], data['email']) | ||
db.session.add(user) | ||
db.session.commit() | ||
return jsonify({"message": "User created successfully"}), 201 | ||
@bp.route('/user/<uuid:user_id>', methods=["GET"]) | ||
@login_required | ||
def get_user(user_id): | ||
"""get a specific user by id""" | ||
user = get_user_by_id(str(user_id)) | ||
if not user: | ||
flash('User not found', 'danger') | ||
return redirect(url_for('main.index')) | ||
return jsonify({"username": user.username, "email": user.email}) | ||
|
||
|
||
@bp.route('/register', methods=['GET', 'POST']) | ||
def register(): | ||
if request.method == 'POST': | ||
data = request.form | ||
first_name = data.get('first_name') | ||
last_name = data.get('last_name') | ||
username = data.get('username') | ||
email = data.get('email') | ||
password = data.get('password') | ||
|
||
if not first_name or not last_name or not username or not email or not password: | ||
flash('All fields are required', 'error') | ||
return redirect(url_for('user_routes.register')) | ||
|
||
existing_user = get_user_by_email(email) | ||
if existing_user: | ||
flash('Email already registered', 'error') | ||
return redirect(url_for('user_routes.register')) | ||
|
||
try: | ||
create_user(first_name, last_name, password, email, username) | ||
flash('Registration successful, proceed to login!', 'success') | ||
return redirect(url_for('auth.login')) | ||
except Exception as e: | ||
db.session.rollback() | ||
flash('An error occured during registeration. Please try again', 'error') | ||
return redirect(url_for('user_routes.register')) | ||
|
||
return render_template('register.html') | ||
|
||
|
||
@bp.route('/user/<uuid:user_id>/edit', methods=["POST"]) | ||
@login_required | ||
def edit_user(user_id): | ||
"""Update user details by id""" | ||
user = get_user_by_id(str(user_id)) | ||
if user and user.id == current_user.id: | ||
data = request.form | ||
new_email = data.get('email') | ||
|
||
# run a quick db check to see if email already exist | ||
all_users = get_all_users() | ||
if any(u.email == new_email and u.id != user.id for u in all_users): | ||
flash('Email already in use', 'danger') | ||
return redirect(url_for('user_routes.get_user', user_id=user_id)) | ||
|
||
update_user( | ||
user, | ||
email=new_email, | ||
password=data.get('password'), | ||
first_name=data.get('first_name'), | ||
last_name=data.get('last_name') | ||
) | ||
|
||
flash('Profile updated successfully', 'success') | ||
return redirect(url_for('user_routes.get_user', user_id=user_id)) | ||
|
||
else: | ||
flash('You are not authorized to edit this profile.', 'danger') | ||
return redirect(url_for('main.index')) | ||
|
||
|
||
@bp.route('/user/<uuid:user_id>/delete', methods=['POST']) | ||
@login_required | ||
def delete_user_profile(user_id): | ||
|
||
user = get_user_by_id(user_id) | ||
if user and user.id == current_user.id: | ||
delete_user(user) | ||
flash('Profile deleted succesfully.', 'success') | ||
return redirect(url_for('main.index')) | ||
else: | ||
flash('You are not authorized to delete this profile.', 'danger') | ||
return redirect(url_for('main.index')) |
Oops, something went wrong.