diff --git a/.gitignore b/.gitignore index e43b0f9..e8d5699 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ .DS_Store +.venv +node_modules diff --git a/backend/data/blooms.py b/backend/data/blooms.py index 7e280cf..b5f4a61 100644 --- a/backend/data/blooms.py +++ b/backend/data/blooms.py @@ -16,27 +16,38 @@ class Bloom: def add_bloom(*, sender: User, content: str) -> Bloom: + # Enforce 280-character limit + content = content.strip() + if len(content) > 280: + content = content[:280] # truncate to 280 characters + hashtags = [word[1:] for word in content.split(" ") if word.startswith("#")] now = datetime.datetime.now(tz=datetime.UTC) bloom_id = int(now.timestamp() * 1000000) + with db_cursor() as cur: cur.execute( - "INSERT INTO blooms (id, sender_id, content, send_timestamp) VALUES (%(bloom_id)s, %(sender_id)s, %(content)s, %(timestamp)s)", + """ + INSERT INTO blooms (id, sender_id, content, send_timestamp) + VALUES (%(bloom_id)s, %(sender_id)s, %(content)s, %(timestamp)s) + """, dict( bloom_id=bloom_id, sender_id=sender.id, content=content, - timestamp=datetime.datetime.now(datetime.UTC), + timestamp=now, ), ) for hashtag in hashtags: cur.execute( - "INSERT INTO hashtags (hashtag, bloom_id) VALUES (%(hashtag)s, %(bloom_id)s)", + """ + INSERT INTO hashtags (hashtag, bloom_id) + VALUES (%(hashtag)s, %(bloom_id)s) + """, dict(hashtag=hashtag, bloom_id=bloom_id), ) - def get_blooms_for_user( username: str, *, before: Optional[int] = None, limit: Optional[int] = None ) -> List[Bloom]: diff --git a/backend/endpoints.py b/backend/endpoints.py index 0e177a0..fccf288 100644 --- a/backend/endpoints.py +++ b/backend/endpoints.py @@ -152,19 +152,35 @@ def do_follow(): @jwt_required() def send_bloom(): - type_check_error = verify_request_fields({"content": str}) - if type_check_error is not None: - return type_check_error - + """Handles POST requests to create a new bloom (post).""" + + # 1. Input Validation: Check for required fields and types + validation_error = verify_request_fields({"content": str}) + if validation_error: + return validation_error + + # 2. Data Extraction and Cleaning + content = request.json.get("content", "").strip() + + # 3. Application-Specific Validation (Length and Empty Check) + if not content: + return jsonify({ + "success": False, + "error": "Content cannot be empty." + }), 400 + + if len(content) > 280: + return jsonify({ + "success": False, + "error": f"Content too long. Maximum 280 characters (current: {len(content)})." + }), 400 + + # 4. Processing: Get user and save the resource user = get_current_user() - - blooms.add_bloom(sender=user, content=request.json["content"]) - - return jsonify( - { - "success": True, - } - ) + blooms.add_bloom(sender=user, content=content) + + # 5. Success Response + return jsonify({"success": True}), 201 def get_bloom(id_str):