stuff changed:
- ui has been made 'kinda better' (after making it worse for a while lol - ESP rfid readers are now supported [ill upload the code for them in another repo later] - admin system has been secured a bit better and seems to be working well
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
from fastapi import APIRouter
|
||||
from . import auth, users, tiers, memberships, payments, email, email_templates, events, feature_flags
|
||||
from . import auth, users, tiers, memberships, payments, email, email_templates, events, feature_flags, esp
|
||||
|
||||
api_router = APIRouter()
|
||||
|
||||
@@ -12,3 +12,4 @@ api_router.include_router(email.router, prefix="/email", tags=["email"])
|
||||
api_router.include_router(email_templates.router, prefix="/email-templates", tags=["email-templates"])
|
||||
api_router.include_router(events.router, prefix="/events", tags=["events"])
|
||||
api_router.include_router(feature_flags.router, prefix="/feature-flags", tags=["feature-flags"])
|
||||
api_router.include_router(esp.router, prefix="/esp", tags=["esp-rfid"])
|
||||
|
||||
@@ -6,6 +6,7 @@ from typing import List
|
||||
import uuid
|
||||
|
||||
from ...core.database import get_db
|
||||
from ...core.datetime import utc_now
|
||||
from ...core.security import verify_password, get_password_hash, create_access_token
|
||||
from ...models.models import User, UserRole, PasswordResetToken
|
||||
from ...schemas import (
|
||||
@@ -85,7 +86,7 @@ async def login(
|
||||
)
|
||||
|
||||
# Update last login
|
||||
user.last_login = datetime.utcnow()
|
||||
user.last_login = utc_now()
|
||||
db.commit()
|
||||
|
||||
# Create access token
|
||||
@@ -120,7 +121,7 @@ async def login_json(
|
||||
)
|
||||
|
||||
# Update last login
|
||||
user.last_login = datetime.utcnow()
|
||||
user.last_login = utc_now()
|
||||
db.commit()
|
||||
|
||||
# Create access token
|
||||
@@ -149,12 +150,12 @@ async def forgot_password(
|
||||
db.query(PasswordResetToken).filter(
|
||||
PasswordResetToken.user_id == user.id,
|
||||
PasswordResetToken.used == False,
|
||||
PasswordResetToken.expires_at > datetime.utcnow()
|
||||
PasswordResetToken.expires_at > utc_now()
|
||||
).update({"used": True})
|
||||
|
||||
# Generate new reset token
|
||||
reset_token = str(uuid.uuid4())
|
||||
expires_at = datetime.utcnow() + timedelta(hours=1) # Token expires in 1 hour
|
||||
expires_at = utc_now() + timedelta(hours=1) # Token expires in 1 hour
|
||||
|
||||
# Create password reset token
|
||||
db_token = PasswordResetToken(
|
||||
@@ -192,7 +193,7 @@ async def reset_password(
|
||||
reset_token = db.query(PasswordResetToken).filter(
|
||||
PasswordResetToken.token == request.token,
|
||||
PasswordResetToken.used == False,
|
||||
PasswordResetToken.expires_at > datetime.utcnow()
|
||||
PasswordResetToken.expires_at > utc_now()
|
||||
).first()
|
||||
|
||||
if not reset_token:
|
||||
@@ -212,7 +213,7 @@ async def reset_password(
|
||||
# Update password
|
||||
hashed_password = get_password_hash(request.new_password)
|
||||
user.hashed_password = hashed_password
|
||||
user.updated_at = datetime.utcnow()
|
||||
user.updated_at = utc_now()
|
||||
|
||||
# Mark token as used
|
||||
reset_token.used = True
|
||||
@@ -239,7 +240,7 @@ async def change_password(
|
||||
# Update password
|
||||
hashed_password = get_password_hash(request.new_password)
|
||||
current_user.hashed_password = hashed_password
|
||||
current_user.updated_at = datetime.utcnow()
|
||||
current_user.updated_at = utc_now()
|
||||
|
||||
db.commit()
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ from ...api.dependencies import get_admin_user
|
||||
from ...models.models import User
|
||||
from typing import Dict, Any, List
|
||||
from ...core.database import get_db
|
||||
from ...core.datetime import to_zulu_iso
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
router = APIRouter()
|
||||
@@ -95,7 +96,7 @@ async def get_bounce_list(
|
||||
"email": bounce.email,
|
||||
"bounce_type": bounce.bounce_type.value,
|
||||
"bounce_reason": bounce.bounce_reason,
|
||||
"bounce_date": bounce.bounce_date.isoformat(),
|
||||
"bounce_date": to_zulu_iso(bounce.bounce_date),
|
||||
"is_active": bounce.is_active,
|
||||
"smtp2go_message_id": bounce.smtp2go_message_id
|
||||
}
|
||||
@@ -132,7 +133,7 @@ async def get_bounce_history(
|
||||
"id": bounce.id,
|
||||
"bounce_type": bounce.bounce_type.value,
|
||||
"bounce_reason": bounce.bounce_reason,
|
||||
"bounce_date": bounce.bounce_date.isoformat(),
|
||||
"bounce_date": to_zulu_iso(bounce.bounce_date),
|
||||
"is_active": bounce.is_active,
|
||||
"smtp2go_message_id": bounce.smtp2go_message_id
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from sqlalchemy.orm import Session
|
||||
from typing import List
|
||||
from datetime import datetime
|
||||
|
||||
from ...core.database import get_db
|
||||
from ...core.datetime import utc_now
|
||||
from ...models.models import Event, EventRSVP, User, EventStatus
|
||||
from ...schemas import (
|
||||
EventCreate, EventUpdate, EventResponse, EventRSVPResponse, EventRSVPUpdate, MessageResponse
|
||||
@@ -13,6 +13,10 @@ from ...api.dependencies import get_current_active_user, get_admin_user
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
def _utc_time_string(value) -> str:
|
||||
return value.strftime("%H:%M")
|
||||
|
||||
|
||||
@router.get("/", response_model=List[EventResponse])
|
||||
async def get_events(
|
||||
current_user: User = Depends(get_current_active_user),
|
||||
@@ -34,9 +38,9 @@ async def get_upcoming_events(
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Get upcoming events"""
|
||||
now = datetime.now()
|
||||
now = utc_now()
|
||||
events = db.query(Event).filter(
|
||||
Event.event_date >= now.date(),
|
||||
Event.event_date >= now,
|
||||
Event.status == EventStatus.PUBLISHED
|
||||
).order_by(Event.event_date).all()
|
||||
return events
|
||||
@@ -50,7 +54,7 @@ async def create_event(
|
||||
):
|
||||
"""Create a new event (admin only)"""
|
||||
# Validate event date is in the future
|
||||
if event_data.event_date < datetime.now():
|
||||
if event_data.event_date < utc_now():
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Event date must be in the future"
|
||||
@@ -60,7 +64,7 @@ async def create_event(
|
||||
title=event_data.title,
|
||||
description=event_data.description,
|
||||
event_date=event_data.event_date,
|
||||
event_time=event_data.event_time,
|
||||
event_time=_utc_time_string(event_data.event_date),
|
||||
location=event_data.location,
|
||||
max_attendees=event_data.max_attendees,
|
||||
status=EventStatus.DRAFT,
|
||||
@@ -89,10 +93,14 @@ async def update_event(
|
||||
)
|
||||
|
||||
# Update fields
|
||||
for field, value in event_data.dict(exclude_unset=True).items():
|
||||
update_data = event_data.model_dump(exclude_unset=True)
|
||||
if "event_date" in update_data:
|
||||
update_data["event_time"] = _utc_time_string(update_data["event_date"])
|
||||
|
||||
for field, value in update_data.items():
|
||||
setattr(event, field, value)
|
||||
|
||||
event.updated_at = datetime.now()
|
||||
event.updated_at = utc_now()
|
||||
db.commit()
|
||||
db.refresh(event)
|
||||
return event
|
||||
@@ -167,7 +175,7 @@ async def create_or_update_rsvp(
|
||||
existing_rsvp.status = rsvp_data.status
|
||||
if rsvp_data.notes is not None:
|
||||
existing_rsvp.notes = rsvp_data.notes
|
||||
existing_rsvp.updated_at = datetime.now()
|
||||
existing_rsvp.updated_at = utc_now()
|
||||
db.commit()
|
||||
db.refresh(existing_rsvp)
|
||||
return existing_rsvp
|
||||
@@ -204,4 +212,4 @@ async def get_my_rsvps(
|
||||
):
|
||||
"""Get current user's RSVPs"""
|
||||
rsvps = db.query(EventRSVP).filter(EventRSVP.user_id == current_user.id).all()
|
||||
return rsvps
|
||||
return rsvps
|
||||
|
||||
@@ -5,6 +5,7 @@ from datetime import datetime, timedelta
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
from ...core.database import get_db
|
||||
from ...core.datetime import unix_ms_utc, utc_now
|
||||
from ...models.models import Payment, PaymentStatus, PaymentMethod, User, Membership, MembershipStatus, MembershipTier
|
||||
from ...schemas import (
|
||||
PaymentCreate, PaymentUpdate, PaymentResponse, MessageResponse,
|
||||
@@ -121,7 +122,7 @@ async def update_payment(
|
||||
|
||||
# If marking as completed, set payment_date if not already set
|
||||
if update_data.get("status") == PaymentStatus.COMPLETED and not payment.payment_date:
|
||||
update_data["payment_date"] = datetime.utcnow()
|
||||
update_data["payment_date"] = utc_now()
|
||||
|
||||
for field, value in update_data.items():
|
||||
setattr(payment, field, value)
|
||||
@@ -182,7 +183,7 @@ async def process_square_payment(
|
||||
)
|
||||
|
||||
# Create a reference ID for tracking
|
||||
reference_id = f"user_{current_user.id}_tier_{tier.id}_{datetime.utcnow().timestamp()}"
|
||||
reference_id = f"user_{current_user.id}_tier_{tier.id}_{unix_ms_utc(utc_now())}"
|
||||
|
||||
# Process payment with Square
|
||||
square_result = await square_service.create_payment(
|
||||
@@ -204,7 +205,7 @@ async def process_square_payment(
|
||||
# Payment succeeded - create membership and payment records in a transaction
|
||||
try:
|
||||
# Calculate membership dates
|
||||
start_date = datetime.utcnow().date()
|
||||
start_date = utc_now().date()
|
||||
end_date = start_date + relativedelta(years=1)
|
||||
|
||||
# Create membership with ACTIVE status
|
||||
@@ -226,7 +227,7 @@ async def process_square_payment(
|
||||
payment_method=PaymentMethod.SQUARE,
|
||||
status=PaymentStatus.COMPLETED,
|
||||
transaction_id=square_result.get('payment_id'),
|
||||
payment_date=datetime.utcnow(),
|
||||
payment_date=utc_now(),
|
||||
notes=payment_request.note
|
||||
)
|
||||
db.add(payment)
|
||||
@@ -389,7 +390,7 @@ async def record_manual_payment(
|
||||
payment_method=payment_data.payment_method,
|
||||
notes=payment_data.notes,
|
||||
status=PaymentStatus.COMPLETED,
|
||||
payment_date=datetime.utcnow()
|
||||
payment_date=utc_now()
|
||||
)
|
||||
|
||||
db.add(payment)
|
||||
|
||||
@@ -7,6 +7,7 @@ from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ...core.database import get_db
|
||||
from ...core.datetime import utc_now
|
||||
from ...models.models import ProfileQuestion, User, UserProfileAnswer, UserRole, PasswordResetToken
|
||||
from ...schemas import (
|
||||
MessageResponse,
|
||||
@@ -691,11 +692,11 @@ async def send_user_password_reset(
|
||||
db.query(PasswordResetToken).filter(
|
||||
PasswordResetToken.user_id == user.id,
|
||||
PasswordResetToken.used == False,
|
||||
PasswordResetToken.expires_at > datetime.utcnow()
|
||||
PasswordResetToken.expires_at > utc_now()
|
||||
).update({"used": True})
|
||||
|
||||
reset_token = str(uuid.uuid4())
|
||||
expires_at = datetime.utcnow() + timedelta(hours=1)
|
||||
expires_at = utc_now() + timedelta(hours=1)
|
||||
|
||||
db_token = PasswordResetToken(
|
||||
user_id=user.id,
|
||||
|
||||
Reference in New Issue
Block a user