diff --git a/.firebaserc b/.firebaserc new file mode 100644 index 0000000..9b5f33e --- /dev/null +++ b/.firebaserc @@ -0,0 +1,5 @@ +{ + "projects": { + "default": "overheard-d7396" + } +} diff --git a/firebase.json b/firebase.json new file mode 100644 index 0000000..4294c24 --- /dev/null +++ b/firebase.json @@ -0,0 +1,12 @@ +{ + "firestore": { + "rules": "firestore.rules", + "indexes": "firestore.indexes.json" + }, + "storage": [ + { + "bucket": "overheard-d7396.firebasestorage.app", + "rules": "storage.rules" + } + ] +} diff --git a/firestore.indexes.json b/firestore.indexes.json new file mode 100644 index 0000000..2ddb5ce --- /dev/null +++ b/firestore.indexes.json @@ -0,0 +1,4 @@ +{ + "indexes": [], + "fieldOverrides": [] +} \ No newline at end of file diff --git a/firestore.rules b/firestore.rules new file mode 100644 index 0000000..ca2b629 --- /dev/null +++ b/firestore.rules @@ -0,0 +1,26 @@ +rules_version = '2'; +service cloud.firestore { + match /databases/{database}/documents { + match /messages/{messageId} { + + // anyone can read messages + allow read: if true; + + // anyone can create a message + // text must exist and be under 240 characters + allow create: if + request.resource.data.text is string && + request.resource.data.text.size() <= 240; + + // the only update allowed is an echo + // echoCount and lastEchoAt fields can be changed + // this prevents anyone from editing the text of someone else's message + allow update: if + request.resource.data.diff(resource.data) + .affectedKeys().hasOnly(['echoCount', 'lastEchoAt']); + + // nobody can delete messages through the client + allow delete: if false; + } + } +} \ No newline at end of file diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..95a70d8 --- /dev/null +++ b/public/index.html @@ -0,0 +1,89 @@ + + +
+ + +You're seeing this because you've successfully setup Firebase Hosting. Now it's time to go build something extraordinary!
+ Open Hosting Documentation +Firebase SDK Loading…
+ + + + diff --git a/src/lib/Firebase/messages.js b/src/lib/Firebase/messages.js index 58d2d0e..1802c02 100644 --- a/src/lib/Firebase/messages.js +++ b/src/lib/Firebase/messages.js @@ -7,6 +7,7 @@ import ngeohash from 'ngeohash'; export async function getNearbyMessages(lat, lng) { const prefix = getQueryPrefix(lat, lng); + // filter by the geohash const q = query( collection(db, 'messages'), where('geohash', '>=', prefix), @@ -30,7 +31,7 @@ export async function getNearbyMessages(lat, lng) { return active; } - +// update the echo counter export async function echoMessage(messageId) { const ref = doc(db, 'messages', messageId); await updateDoc(ref, { @@ -39,6 +40,7 @@ export async function echoMessage(messageId) { }); } +// adding the message location export async function addMessage(lat, lng, text, imageUrl = ''){ const geohash = ngeohash.encode(lat, lng, 6); @@ -55,6 +57,7 @@ export async function addMessage(lat, lng, text, imageUrl = ''){ }); } +// session ID (temporary) function getSessionId() { let id = localStorage.getItem('overheard_session'); if (!id) { diff --git a/src/lib/Firebase/storage.js b/src/lib/Firebase/storage.js index 47d2a48..dd6fcbc 100644 --- a/src/lib/Firebase/storage.js +++ b/src/lib/Firebase/storage.js @@ -1,6 +1,7 @@ import { ref, uploadBytes, getDownloadURL } from 'firebase/storage' import { storage } from './config.js'; + export async function uploadImage(file) { //create unique file name and stores them in one folder in firebase const filename = `messages/${Date.now()}_${file.name}`; diff --git a/src/lib/components/MapView.Svelte b/src/lib/components/MapView.Svelte index 7158fe8..a3994e3 100644 --- a/src/lib/components/MapView.Svelte +++ b/src/lib/components/MapView.Svelte @@ -8,15 +8,16 @@ // export let longitude; // ^ this didn't work for some reason, so instead we get the props like this: (based on internet research this is the fix) let { lat, lng } = $props(); - +s let mapDiv; + let map = $state(null); let markers = []; // keep track of pins on map let userMarker; let AdvancedMarkerElement; /** Jisu Legacy - λ΄ μμΉ λ§μ»€ (λ©μμ§ νκ³Ό ꡬλΆλλ νλ μ ) */ - function addUserLocationMarker(map, centerLat, centerLng) { + function addUserLocationMarker(centerLat, centerLng) { const dot = document.createElement('div'); dot.style.cssText = 'width:20px;height:20px;border-radius:50%;background:#4285F4;border:3px solid #fff;box-shadow:0 2px 6px rgba(0,0,0,0.3)'; userMarker = new AdvancedMarkerElement({ @@ -41,7 +42,7 @@ const { Map } = await importLibrary('maps'); ({ AdvancedMarkerElement } = await importLibrary('marker')); - mapDiv = new Map(mapDiv, { + map = new Map(mapDiv, { center: { lat: centerLat, lng: centerLng }, zoom: 15, disableDefaultUI: true, @@ -49,7 +50,7 @@ mapId: 'DEMO_MAP_ID' }); - addUserLocationMarker(mapDiv, centerLat, centerLng); + addUserLocationMarker(centerLat, centerLng); }); // function to render pins @@ -61,7 +62,7 @@ messages.forEach(message => { const marker = new AdvancedMarkerElement({ position: { lat: message.lat, lng: message.lng }, - map: mapDiv, + map, title: message.text }); @@ -75,7 +76,7 @@ // this is a reactive statement so anytime the store changes it updates $effect(() => { - if (mapDiv && $messagesStore.length > 0 ){ // if they both exist + if (map && $messagesStore.length > 0 ){ // if they both exist renderPins($messagesStore); // we put pins on the map } }) diff --git a/storage.rules b/storage.rules new file mode 100644 index 0000000..ec2112a --- /dev/null +++ b/storage.rules @@ -0,0 +1,20 @@ +rules_version = '2'; + +service firebase.storage { + match /b/{bucket}/o { + match /messages/{fileName} { + + // anyone can view uploaded images + allow read: if true; + + // anyone can upload an image attached to a message + // must be an image under 5MB + allow create: if + request.resource.size < 5 * 1024 * 1024 && + request.resource.contentType.matches('image/.*'); + + // no edits or deletes through the client + allow update, delete: if false; + } + } +}