diff --git a/backend/data/blooms.py b/backend/data/blooms.py index 7e280cf..b5eb03a 100644 --- a/backend/data/blooms.py +++ b/backend/data/blooms.py @@ -16,6 +16,9 @@ class Bloom: def add_bloom(*, sender: User, content: str) -> Bloom: + # // 280 char limit + if len(content) > 280: + return {"error": "Too long!"}, 400 hashtags = [word[1:] for word in content.split(" ") if word.startswith("#")] now = datetime.datetime.now(tz=datetime.UTC) diff --git a/backend/data/users.py b/backend/data/users.py index 00746f1..71494c7 100644 --- a/backend/data/users.py +++ b/backend/data/users.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from hashlib import scrypt +# from hashlib import scrypt import hashlib import random import string @@ -90,8 +90,10 @@ def register_user(username: str, password_plaintext: str) -> User: raise UserRegistrationError("user already exists") +# def scrypt(password_plaintext: bytes, password_salt: bytes) -> bytes: +# return hashlib.scrypt(password_plaintext, salt=password_salt, n=8, r=8, p=1) def scrypt(password_plaintext: bytes, password_salt: bytes) -> bytes: - return hashlib.scrypt(password_plaintext, salt=password_salt, n=8, r=8, p=1) + return hashlib.pbkdf2_hmac('sha256', password_plaintext, password_salt, 100000) SALT_CHARACTERS = string.ascii_uppercase + string.ascii_lowercase + string.digits diff --git a/front-end/components/bloom-form.mjs b/front-end/components/bloom-form.mjs index e047f9a..544f653 100644 --- a/front-end/components/bloom-form.mjs +++ b/front-end/components/bloom-form.mjs @@ -1,4 +1,4 @@ -import {apiService} from "../index.mjs"; +import { apiService } from "../index.mjs"; /** * Create a bloom form component @@ -7,12 +7,12 @@ import {apiService} from "../index.mjs"; * @returns {DocumentFragment} - The bloom form fragment */ function createBloomForm(template, isLoggedIn) { - if (!isLoggedIn) return; - const bloomFormElement = document - .getElementById(template) - .content.cloneNode(true); + if (!isLoggedIn) return; + const bloomFormElement = document + .getElementById(template) + .content.cloneNode(true); - return bloomFormElement; + return bloomFormElement; } /** @@ -20,26 +20,32 @@ function createBloomForm(template, isLoggedIn) { * @param {Event} event - The form submission event */ async function handleBloomSubmit(event) { - event.preventDefault(); - const form = event.target; - const submitButton = form.querySelector("[data-submit]"); - const originalText = submitButton.textContent; - const textarea = form.querySelector("textarea"); - const content = textarea.value.trim(); + event.preventDefault(); + const form = event.target; + const submitButton = form.querySelector("[data-submit]"); + const originalText = submitButton.textContent; + const textarea = form.querySelector("textarea"); + const content = textarea.value.trim(); - try { - // Make form inert while we call the back end - form.inert = true; - submitButton.textContent = "Posting..."; - await apiService.postBloom(content); - textarea.value = ""; - } catch (error) { - throw error; - } finally { - // Restore form - submitButton.textContent = originalText; - form.inert = false; - } + //add char limit + if (content.length > 280) { + alert("Too long! Maximum 280 characters."); + return; + } + + try { + // Make form inert while we call the back end + form.inert = true; + submitButton.textContent = "Posting..."; + await apiService.postBloom(content); + textarea.value = ""; + } catch (error) { + throw error; + } finally { + // Restore form + submitButton.textContent = originalText; + form.inert = false; + } } /** @@ -47,12 +53,12 @@ async function handleBloomSubmit(event) { * @param {Event} event - The input event from textarea drives the character counter */ function handleTyping(event) { - const textarea = event.target; - const counter = textarea - .closest("[data-form]") - ?.querySelector("[data-counter]"); - const maxLength = parseInt(textarea.getAttribute("maxlength"), 10); - counter.textContent = `${textarea.value.length} / ${maxLength}`; + const textarea = event.target; + const counter = textarea + .closest("[data-form]") + ?.querySelector("[data-counter]"); + const maxLength = parseInt(textarea.getAttribute("maxlength"), 10); + counter.textContent = `${textarea.value.length} / ${maxLength}`; } -export {createBloomForm, handleBloomSubmit, handleTyping}; +export { createBloomForm, handleBloomSubmit, handleTyping }; diff --git a/front-end/views/profile.mjs b/front-end/views/profile.mjs index dd2b92a..9824d9c 100644 --- a/front-end/views/profile.mjs +++ b/front-end/views/profile.mjs @@ -1,66 +1,69 @@ -import {renderEach, renderOne, destroy} from "../lib/render.mjs"; +import { renderEach, renderOne, destroy } from "../lib/render.mjs"; import { - apiService, - state, - getLogoutContainer, - getLoginContainer, - getProfileContainer, - getTimelineContainer, + apiService, + state, + getLogoutContainer, + getLoginContainer, + getProfileContainer, + getTimelineContainer, } from "../index.mjs"; -import {createLogin, handleLogin} from "../components/login.mjs"; -import {createLogout, handleLogout} from "../components/logout.mjs"; -import {createProfile, handleFollow} from "../components/profile.mjs"; -import {createBloom} from "../components/bloom.mjs"; +import { createLogin, handleLogin } from "../components/login.mjs"; +import { createLogout, handleLogout } from "../components/logout.mjs"; +import { createProfile, handleFollow } from "../components/profile.mjs"; +import { createBloom } from "../components/bloom.mjs"; // Profile view - just this person's blooms and their profile function profileView(username) { - destroy(); + destroy(); - const existingProfile = state.profiles.find((p) => p.username === username); + const existingProfile = state.profiles.find((p) => p.username === username); - // Only fetch profile if we don't have it or if it's incomplete - if (!existingProfile || !existingProfile.recent_blooms) { - apiService.getProfile(username); - } + // Only fetch profile if we don't have it or if it's incomplete + if (!existingProfile || !existingProfile.recent_blooms) { + apiService.getProfile(username); + } - renderOne( - state.isLoggedIn, - getLogoutContainer(), - "logout-template", - createLogout - ); - document - .querySelector("[data-action='logout']") - ?.addEventListener("click", handleLogout); - renderOne( - state.isLoggedIn, - getLoginContainer(), - "login-template", - createLogin - ); - document - .querySelector("[data-action='login']") - ?.addEventListener("click", handleLogin); + renderOne( + state.isLoggedIn, + getLogoutContainer(), + "logout-template", + createLogout + ); + document + .querySelector("[data-action='logout']") + ?.addEventListener("click", handleLogout); + renderOne( + state.isLoggedIn, + getLoginContainer(), + "login-template", + createLogin + ); + document + // .querySelector("[data-action='login']") + // ?.addEventListener("click", handleLogin); + .querySelector(".login__form") + ?.addEventListener("submit", handleLogin); + //submit event gets data from inputs - const profileData = state.profiles.find((p) => p.username === username); - if (profileData) { - renderOne( - { - profileData, - whoToFollow: state.isLoggedIn ? state.whoToFollow : [], - isLoggedIn: state.isLoggedIn, - }, - getProfileContainer(), - "profile-template", - createProfile - ); - renderEach( - profileData.recent_blooms || [], - getTimelineContainer(), - "bloom-template", - createBloom - ); - } + const profileData = state.profiles.find((p) => p.username === username); + if (profileData) { + renderOne( + { + profileData, + whoToFollow: state.isLoggedIn ? state.whoToFollow : [], + isLoggedIn: state.isLoggedIn, + }, + getProfileContainer(), + "profile-template", + createProfile + ); + renderEach( + profileData.recent_blooms || [], + getTimelineContainer(), + "bloom-template", + createBloom + ); + } } -export {profileView}; +export { profileView };