Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"liveServer.settings.root": "front-end/",
"python.defaultInterpreterPath": "backend/.venv/bin/python"
"python.defaultInterpreterPath": "backend/.venv/bin/python",
"liveServer.settings.port": 5500
}
21 changes: 13 additions & 8 deletions backend/data/blooms.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,23 @@
class Bloom:
id: int
sender: User
original_sender: str
content: str
sent_timestamp: datetime.datetime


def add_bloom(*, sender: User, content: str) -> Bloom:
def add_bloom(*, sender: User, original_sender: str, content: str) -> Bloom:
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, original_sender, content, send_timestamp) VALUES (%(bloom_id)s, %(sender_id)s, %(original_sender)s, %(content)s, %(timestamp)s)",
dict(
bloom_id=bloom_id,
sender_id=sender.id,
original_sender=original_sender,
content=content,
timestamp=datetime.datetime.now(datetime.UTC),
),
Expand Down Expand Up @@ -54,7 +56,7 @@ def get_blooms_for_user(

cur.execute(
f"""SELECT
blooms.id, users.username, content, send_timestamp
blooms.id, users.username, original_sender, content, send_timestamp
FROM
blooms INNER JOIN users ON users.id = blooms.sender_id
WHERE
Expand All @@ -68,11 +70,12 @@ def get_blooms_for_user(
rows = cur.fetchall()
blooms = []
for row in rows:
bloom_id, sender_username, content, timestamp = row
bloom_id, sender_username, original_sender, content, timestamp = row
blooms.append(
Bloom(
id=bloom_id,
sender=sender_username,
original_sender=original_sender,
content=content,
sent_timestamp=timestamp,
)
Expand All @@ -83,16 +86,17 @@ def get_blooms_for_user(
def get_bloom(bloom_id: int) -> Optional[Bloom]:
with db_cursor() as cur:
cur.execute(
"SELECT blooms.id, users.username, content, send_timestamp FROM blooms INNER JOIN users ON users.id = blooms.sender_id WHERE blooms.id = %s",
"SELECT blooms.id, users.username, original_sender, content, send_timestamp FROM blooms INNER JOIN users ON users.id = blooms.sender_id WHERE blooms.id = %s",
(bloom_id,),
)
row = cur.fetchone()
if row is None:
return None
bloom_id, sender_username, content, timestamp = row
bloom_id, sender_username, original_sender, content, timestamp = row
return Bloom(
id=bloom_id,
sender=sender_username,
original_sender=original_sender,
content=content,
sent_timestamp=timestamp,
)
Expand All @@ -108,7 +112,7 @@ def get_blooms_with_hashtag(
with db_cursor() as cur:
cur.execute(
f"""SELECT
blooms.id, users.username, content, send_timestamp
blooms.id, users.username, original_sender, content, send_timestamp
FROM
blooms INNER JOIN hashtags ON blooms.id = hashtags.bloom_id INNER JOIN users ON blooms.sender_id = users.id
WHERE
Expand All @@ -121,11 +125,12 @@ def get_blooms_with_hashtag(
rows = cur.fetchall()
blooms = []
for row in rows:
bloom_id, sender_username, content, timestamp = row
bloom_id, sender_username, original_sender, content, timestamp = row
blooms.append(
Bloom(
id=bloom_id,
sender=sender_username,
original_sender=original_sender,
content=content,
sent_timestamp=timestamp,
)
Expand Down
5 changes: 4 additions & 1 deletion backend/endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,11 @@ def send_bloom():
return type_check_error

user = get_current_user()
original_sender = None
if request.json.get("original_sender"):
original_sender = request.json["original_sender"]

blooms.add_bloom(sender=user, content=request.json["content"])
blooms.add_bloom(sender=user, original_sender=original_sender, content=request.json["content"])

return jsonify(
{
Expand Down
1 change: 1 addition & 0 deletions db/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ CREATE TABLE users (
CREATE TABLE blooms (
id BIGSERIAL NOT NULL PRIMARY KEY,
sender_id INT NOT NULL REFERENCES users(id),
original_sender TEXT DEFAULT NULL,
content TEXT NOT NULL,
send_timestamp TIMESTAMP NOT NULL
);
Expand Down
21 changes: 20 additions & 1 deletion front-end/components/bloom.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,43 @@
* btw a bloom object is composed thus
* {"id": Number,
* "sender": username,
* "original_sender": "original username", -- or null if this bloom is not reposted
* "content": "string from textarea",
* "sent_timestamp": "datetime as ISO 8601 formatted string"}

*/
import { apiService, state } from "../index.mjs";

const createBloom = (template, bloom) => {
if (!bloom) return;
const bloomFrag = document.getElementById(template).content.cloneNode(true);
const bloomParser = new DOMParser();

const bloomArticle = bloomFrag.querySelector("[data-bloom]");
const bloomUsername = bloomFrag.querySelector("[data-username]");
const bloomOriginalUsername = bloomFrag.querySelector("[data-original-username]");
const bloomTime = bloomFrag.querySelector("[data-time]");
const bloomTimeLink = bloomFrag.querySelector("a:has(> [data-time])");
const bloomContent = bloomFrag.querySelector("[data-content]");

const reBloomButton = bloomFrag.querySelector("[data-rebloom]");
const currentUser = state["currentUser"];
if (currentUser !== bloom.sender){
reBloomButton.addEventListener("click", async () =>{
const response = await apiService.reBloom(bloom.id);
});
} else {
//this part prevents user from reblooming his own posts
reBloomButton.remove();
}

bloomArticle.setAttribute("data-bloom-id", bloom.id);
bloomUsername.setAttribute("href", `/profile/${bloom.sender}`);
bloomUsername.textContent = bloom.sender;
if (bloom.original_sender){
bloomUsername.textContent = "Rebllomed by: " + bloom.sender;
bloomOriginalUsername.setAttribute("href", `/profile/${bloom.original_sender}`);
bloomOriginalUsername.textContent = "Originaly bloomed by: " + bloom.original_sender;
}
bloomTime.textContent = _formatTimestamp(bloom.sent_timestamp);
bloomTimeLink.setAttribute("href", `/bloom/${bloom.id}`);
bloomContent.replaceChildren(
Expand Down
5 changes: 5 additions & 0 deletions front-end/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -267,3 +267,8 @@ dialog {
[hidden] {
display: none !important;
}

.rebloom {
width: 200px;
margin: 5px auto;
}
2 changes: 2 additions & 0 deletions front-end/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -236,10 +236,12 @@ <h2 id="bloom-form-title" class="bloom-form__title">Share a Bloom</h2>
<article class="bloom box" data-bloom data-bloom-id="">
<div class="bloom__header flex">
<a href="#" class="bloom__username" data-username>Username</a>
<a href="#" class="bloom__original__username" data-original-username>***</a>
<a href="#" class="bloom__time"><time class="bloom__time" data-time>2m</time></a>
</div>
<div class="bloom__content" data-content></div>
</article>
<button class="rebloom" data-rebloom>Rebloom</button>
</template>

<!-- Error Dialog Template -->
Expand Down
22 changes: 19 additions & 3 deletions front-end/lib/api.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -193,25 +193,40 @@ async function getBloomsByHashtag(hashtag) {
}
}

async function postBloom(content) {
async function postBloom(content, original_sender=null) {
try {
const data = await _apiRequest("/bloom", {
method: "POST",
body: JSON.stringify({content}),
body: JSON.stringify({
content: content,
original_sender: original_sender
}),
});

if (data.success) {
await getBlooms();
await getProfile(state.currentUser);
}

return data;
} catch (error) {
// Error already handled by _apiRequest
return {success: false};
}
}

async function reBloom(bloomId){
try {
const bloom = await getBloom(bloomId);
if (!bloom.original_sender){
bloom.original_sender = bloom.sender;
}
await postBloom(bloom.content, bloom.original_sender);
return bloom.content;
} catch (error) {
console.log(error)
}
}

// ======= USER methods
async function getProfile(username) {
const endpoint = username ? `/profile/${username}` : "/profile";
Expand Down Expand Up @@ -292,6 +307,7 @@ const apiService = {
getBlooms,
postBloom,
getBloomsByHashtag,
reBloom,

// User methods
getProfile,
Expand Down