start-suite / app.py
ayush-thakur02's picture
Upload 8 files
b07efa0 verified
from flask import Flask, render_template, request, jsonify, session, redirect, url_for
from pymongo import MongoClient
from werkzeug.security import generate_password_hash, check_password_hash
from datetime import datetime, timedelta
import os
from functools import wraps
import uuid
import base64
import random
from dotenv import load_dotenv
load_dotenv()
app = Flask(__name__)
app.secret_key = os.urandom(24)
# Configure session to be permanent and last for 30 days
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=30)
app.config['SESSION_COOKIE_SECURE'] = False # Set to True in production with HTTPS
app.config['SESSION_COOKIE_HTTPONLY'] = True
app.config['SESSION_COOKIE_SAMESITE'] = 'Lax'
# MongoDB connection
MONGO_URI = os.getenv('MONGO_URI')
client = MongoClient(MONGO_URI)
db = client.startpage
# Collections
users = db.users
user_bookmarks = db.bookmarks
user_notes = db.notes
site_stats = db.site_stats
vault_passwords = db.vault_passwords
def login_required(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if 'user_id' not in session:
return jsonify({'error': 'Authentication required'}), 401
return f(*args, **kwargs)
return decorated_function
@app.route('/')
def index():
# Track page visit
today = datetime.now().strftime('%Y-%m-%d')
site_stats.update_one(
{'date': today},
{'$inc': {'page_visits': 1}},
upsert=True
)
# Check if user is logged in
if 'user_id' not in session:
return render_template('auth.html')
return render_template('index.html', username=session.get('username', 'User'))
@app.route('/register', methods=['POST'])
def register():
data = request.json
username = data.get('username')
password = data.get('password')
if not username or not password:
return jsonify({'error': 'Username and password required'}), 400
if users.find_one({'username': username}):
return jsonify({'error': 'Username already exists'}), 400
user_id = str(uuid.uuid4())
hashed_password = generate_password_hash(password)
users.insert_one({
'user_id': user_id,
'username': username,
'password': hashed_password,
'created_at': datetime.now()
})
# Add default bookmarks for new user
default_bookmarks = [
{ 'name': 'YouTube', 'url': 'https://youtube.com', 'icon': 'play_circle', 'user_id': user_id, 'created_at': datetime.now() },
{ 'name': 'GitHub', 'url': 'https://github.com', 'icon': 'code', 'user_id': user_id, 'created_at': datetime.now() },
{ 'name': 'Gmail', 'url': 'https://gmail.com', 'icon': 'mail', 'user_id': user_id, 'created_at': datetime.now() },
{ 'name': 'Google Drive', 'url': 'https://drive.google.com', 'icon': 'cloud', 'user_id': user_id, 'created_at': datetime.now() },
{ 'name': 'Netflix', 'url': 'https://netflix.com', 'icon': 'movie', 'user_id': user_id, 'created_at': datetime.now() },
{ 'name': 'Reddit', 'url': 'https://reddit.com', 'icon': 'forum', 'user_id': user_id, 'created_at': datetime.now() },
{ 'name': 'Twitter', 'url': 'https://twitter.com', 'icon': 'alternate_email', 'user_id': user_id, 'created_at': datetime.now() },
{ 'name': 'LinkedIn', 'url': 'https://linkedin.com', 'icon': 'work', 'user_id': user_id, 'created_at': datetime.now() }
]
user_bookmarks.insert_many(default_bookmarks)
# Make session permanent so it persists across browser sessions
session.permanent = True
session['user_id'] = user_id
session['username'] = username
return jsonify({'message': 'Registration successful'})
@app.route('/login', methods=['POST'])
def login():
data = request.json
username = data.get('username')
password = data.get('password')
remember_me = data.get('rememberMe', True) # Default to True for backward compatibility
if not username or not password:
return jsonify({'error': 'Username and password required'}), 400
user = users.find_one({'username': username})
if not user or not check_password_hash(user['password'], password):
return jsonify({'error': 'Invalid credentials'}), 401
# Set session permanence based on user choice
session.permanent = remember_me
session['user_id'] = user['user_id']
session['username'] = username
session['remember_me'] = remember_me
return jsonify({'message': 'Login successful'})
@app.route('/logout', methods=['POST'])
def logout():
session.clear()
return jsonify({'message': 'Logout successful'})
@app.route('/api/bookmarks', methods=['GET'])
@login_required
def get_bookmarks():
user_id = session['user_id']
bookmarks = list(user_bookmarks.find({'user_id': user_id}, {'_id': 0}))
return jsonify(bookmarks)
@app.route('/api/bookmarks', methods=['POST'])
@login_required
def save_bookmarks():
user_id = session['user_id']
data = request.json
user_bookmarks.delete_many({'user_id': user_id})
for bookmark in data.get('bookmarks', []):
bookmark['user_id'] = user_id
bookmark['created_at'] = datetime.now()
user_bookmarks.insert_one(bookmark)
return jsonify({'message': 'Bookmarks saved'})
@app.route('/api/notes', methods=['GET'])
@login_required
def get_notes():
user_id = session['user_id']
notes = list(user_notes.find({'user_id': user_id}, {'_id': 0}))
return jsonify(notes)
@app.route('/api/notes', methods=['POST'])
@login_required
def save_notes():
user_id = session['user_id']
data = request.json
user_notes.delete_many({'user_id': user_id})
for note in data.get('notes', []):
note['user_id'] = user_id
note['updated_at'] = datetime.now()
user_notes.insert_one(note)
return jsonify({'message': 'Notes saved'})
@app.route('/api/search', methods=['POST'])
@login_required
def track_search():
today = datetime.now().strftime('%Y-%m-%d')
site_stats.update_one(
{'date': today},
{'$inc': {'search_count': 1}},
upsert=True
)
return jsonify({'message': 'Search tracked'})
@app.route('/api/stats', methods=['GET'])
def get_stats():
today = datetime.now().strftime('%Y-%m-%d')
stats = site_stats.find_one({'date': today})
if not stats:
return jsonify({'page_visits': 0, 'search_count': 0})
return jsonify({
'page_visits': stats.get('page_visits', 0),
'search_count': stats.get('search_count', 0)
})
@app.route('/api/change-password', methods=['POST'])
@login_required
def change_password():
data = request.json
current_password = data.get('currentPassword')
new_password = data.get('newPassword')
if not current_password or not new_password:
return jsonify({'error': 'Current password and new password required'}), 400
user_id = session['user_id']
user = users.find_one({'user_id': user_id})
if not user or not check_password_hash(user['password'], current_password):
return jsonify({'error': 'Current password is incorrect'}), 400
if len(new_password) < 6:
return jsonify({'error': 'Password must be at least 6 characters long'}), 400
# Update password
hashed_password = generate_password_hash(new_password)
users.update_one(
{'user_id': user_id},
{'$set': {'password': hashed_password, 'updated_at': datetime.now()}}
)
return jsonify({'message': 'Password changed successfully'})
@app.route('/api/developer-stats', methods=['GET'])
@login_required
def get_developer_stats():
# Total users count
total_users = users.count_documents({})
# Total visits and searches across all time
all_stats = list(site_stats.find({}))
total_visits = sum(stat.get('page_visits', 0) for stat in all_stats)
total_searches = sum(stat.get('search_count', 0) for stat in all_stats)
# Monthly data (last 12 months)
monthly_data = []
current_date = datetime.now()
for i in range(12):
# Calculate the first day of each month
target_date = datetime(current_date.year, current_date.month - i, 1) if current_date.month - i > 0 else datetime(current_date.year - 1, current_date.month - i + 12, 1)
# Find all stats for that month
start_of_month = target_date
if target_date.month == 12:
end_of_month = datetime(target_date.year + 1, 1, 1)
else:
end_of_month = datetime(target_date.year, target_date.month + 1, 1)
# Query stats for the month
month_stats = site_stats.aggregate([
{
'$match': {
'date': {
'$gte': start_of_month.strftime('%Y-%m-%d'),
'$lt': end_of_month.strftime('%Y-%m-%d')
}
}
},
{
'$group': {
'_id': None,
'total_visits': {'$sum': '$page_visits'},
'total_searches': {'$sum': '$search_count'}
}
}
])
month_result = list(month_stats)
month_name = target_date.strftime('%b')
if month_result:
monthly_data.append({
'month': month_name,
'visits': month_result[0]['total_visits'],
'searches': month_result[0]['total_searches']
})
else:
monthly_data.append({
'month': month_name,
'visits': 0,
'searches': 0
})
# Reverse to get chronological order
monthly_data.reverse()
return jsonify({
'totalUsers': total_users,
'totalVisits': total_visits,
'totalSearches': total_searches,
'monthlyData': monthly_data
})
# Vault API endpoints
@app.route('/api/vault/authenticate', methods=['POST'])
@login_required
def authenticate_vault():
data = request.json
password = data.get('password')
if not password:
return jsonify({'error': 'Password required'}), 400
user_id = session['user_id']
user = users.find_one({'user_id': user_id})
if not user or not check_password_hash(user['password'], password):
return jsonify({'error': 'Invalid password'}), 401
return jsonify({'message': 'Authentication successful'})
@app.route('/api/vault/passwords', methods=['GET'])
@login_required
def get_vault_passwords():
user_id = session['user_id']
passwords = list(vault_passwords.find({'user_id': user_id}, {'_id': 0}))
# Decode passwords for display (simple base64 encoding for demo)
for password in passwords:
try:
password['password'] = base64.b64decode(password['password'].encode()).decode()
except:
pass # Keep original if decoding fails
return jsonify(passwords)
@app.route('/api/vault/passwords', methods=['POST'])
@login_required
def save_vault_password():
user_id = session['user_id']
data = request.json
# Validate required fields
if not data.get('title') or not data.get('password'):
return jsonify({'error': 'Title and password are required'}), 400
# Simple base64 encoding for password storage (demo purposes)
encoded_password = base64.b64encode(data['password'].encode()).decode()
password_entry = {
'user_id': user_id,
'title': data.get('title'),
'username': data.get('username', ''),
'password': encoded_password,
'website': data.get('website', ''),
'notes': data.get('notes', ''),
'created_at': datetime.now(),
'updated_at': datetime.now()
}
# Check if updating existing entry
if data.get('id'):
password_entry['id'] = data['id']
vault_passwords.update_one(
{'user_id': user_id, 'id': data['id']},
{'$set': password_entry}
)
else:
password_entry['id'] = str(uuid.uuid4())
vault_passwords.insert_one(password_entry)
return jsonify({'message': 'Password saved successfully'})
@app.route('/api/vault/passwords/<password_id>', methods=['DELETE'])
@login_required
def delete_vault_password(password_id):
user_id = session['user_id']
result = vault_passwords.delete_one({
'user_id': user_id,
'id': password_id
})
if result.deleted_count > 0:
return jsonify({'message': 'Password deleted successfully'})
else:
return jsonify({'error': 'Password not found'}), 404
if __name__ == '__main__':
app.run(debug=True, port=7860)