mirror of
https://github.com/donavon04/DocuCenter.git
synced 2025-01-18 01:30:57 -07:00
So many changes!
This commit is contained in:
parent
08b58ee729
commit
1de113913b
@ -0,0 +1 @@
|
||||
MONGODB_URI='mongodb://localhost:27017'
|
@ -3,12 +3,17 @@ const express = require('express');
|
||||
const { MongoClient, ObjectId } = require('mongodb');
|
||||
const cors = require('cors');
|
||||
const app = express();
|
||||
require('dotenv').config();
|
||||
|
||||
|
||||
const port = process.env.PORT || 3000;
|
||||
const mongodb_uri = process.env.MONGODB_URI || 'mongodb://localhost:27017';
|
||||
const mongodb_name = process.env.MONGODB_NAME || 'docucenter';
|
||||
|
||||
if(process.env.MONGODB_URI){
|
||||
console.log("Using ENV: " + process.env.MONGODB_URI);
|
||||
}
|
||||
|
||||
// Parse JSON bodies
|
||||
app.use(express.json({ limit: '50mb' })); // For JSON data
|
||||
app.use(express.urlencoded({ limit: '50mb', extended: true })); // For URL-encoded data
|
||||
@ -112,14 +117,14 @@ app.get('/documents/:id', async (req, res) => {
|
||||
// Update a document
|
||||
app.put('/documents/:id', async (req, res) => {
|
||||
const { id } = req.params;
|
||||
const { title, body } = req.body;
|
||||
const { title, body, tags, edited_by } = req.body;
|
||||
if (!title || !body) {
|
||||
return res.status(400).json({ error: 'Title and body are required' });
|
||||
}
|
||||
try {
|
||||
const result = await db.collection('documents').updateOne(
|
||||
{ _id: new ObjectId(id) },
|
||||
{ $set: { title, body, updated_at: new Date() } }
|
||||
{ $set: { title, body, tags, edited_by, updated_at: new Date() } }
|
||||
);
|
||||
if (result.matchedCount === 0) {
|
||||
return res.status(404).json({ error: 'Document not found' });
|
||||
@ -211,4 +216,5 @@ app.use((req, res) => {
|
||||
// Start the server
|
||||
app.listen(port, () => {
|
||||
console.log(`Server running on http://localhost:${port}`);
|
||||
console.log("Searching for database: URI: "+mongodb_uri);
|
||||
});
|
1
backend/package-lock.json
generated
1
backend/package-lock.json
generated
@ -332,7 +332,6 @@
|
||||
"version": "16.4.7",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
|
||||
"integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==",
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
|
@ -0,0 +1 @@
|
||||
BACKEND_URI='http://localhost:3000'
|
12
frontend/package-lock.json
generated
12
frontend/package-lock.json
generated
@ -25,6 +25,7 @@
|
||||
"@tiptap/extension-underline": "^2.10.3",
|
||||
"@tiptap/pm": "^2.10.3",
|
||||
"@tiptap/starter-kit": "^2.10.3",
|
||||
"dotenv": "^16.4.7",
|
||||
"tippy.js": "^6.3.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -2046,6 +2047,17 @@
|
||||
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "16.4.7",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
|
||||
"integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://dotenvx.com"
|
||||
}
|
||||
},
|
||||
"node_modules/eastasianwidth": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
|
||||
|
@ -51,6 +51,7 @@
|
||||
"@tiptap/extension-underline": "^2.10.3",
|
||||
"@tiptap/pm": "^2.10.3",
|
||||
"@tiptap/starter-kit": "^2.10.3",
|
||||
"dotenv": "^16.4.7",
|
||||
"tippy.js": "^6.3.7"
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
export function setHTML(html){
|
||||
editor.commands.insertContent(html);
|
||||
//initialHTML = html;
|
||||
}
|
||||
|
||||
export function getHTML(){
|
||||
|
@ -25,7 +25,7 @@
|
||||
<i class="fa-solid fa-chevron-down ml-2 mr-2" style="color: #FFFFFF;"></i>
|
||||
{/if}
|
||||
{:else}
|
||||
<p class="font-bold text-white ml-1">Not Signed In</p>
|
||||
<i class="fa-solid fa-right-to-bracket" style="color: #FFFFFF;"></i>
|
||||
<i class="fa-solid fa-chevron-down ml-2 mr-2" style="color: #FFFFFF;"></i>
|
||||
{/if}
|
||||
</button>
|
||||
|
@ -5,15 +5,15 @@
|
||||
<script>
|
||||
import { page } from "$app/stores"
|
||||
import Tiptap from '$lib/components/Tiptap.svelte'
|
||||
import { PUBLIC_BASE_URL } from '$env/static/public';
|
||||
|
||||
let editorRef; //This is our reference to the tiptap editor
|
||||
let document = {}; // To store fetched document data
|
||||
|
||||
let title = "";
|
||||
|
||||
async function save() {
|
||||
const url = "http://localhost:3000/documents";
|
||||
|
||||
console.log("Title value:", title);
|
||||
const url = PUBLIC_BASE_URL+"/documents";
|
||||
|
||||
let created_by = $page.data.session.user?.name ?? "User";
|
||||
|
||||
@ -31,11 +31,10 @@
|
||||
title,
|
||||
body,
|
||||
tags,
|
||||
created_by
|
||||
created_by,
|
||||
visibility
|
||||
};
|
||||
|
||||
console.log(payload);
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method: "POST",
|
||||
@ -68,21 +67,22 @@
|
||||
tags = tags.filter(t => t !== tag); // Filter out the tag from the array
|
||||
}
|
||||
|
||||
// Function to add a tag
|
||||
function addTag() {
|
||||
const tagInput = document.querySelector('#tag');
|
||||
// Ensure the global `document` is used
|
||||
const tagInput = window.document.querySelector('#tag');
|
||||
const tag = tagInput.value.trim(); // Get input value and trim whitespace
|
||||
if (tag && !tags.includes(tag)) { // Ensure non-empty and no duplicates
|
||||
tags = [...tags, tag]; // Create a new array to trigger reactivity
|
||||
}
|
||||
tagInput.value = ''; // Clear the input field
|
||||
}
|
||||
|
||||
let dropMenu = false;
|
||||
let visibility = 'Public';
|
||||
</script>
|
||||
|
||||
<div class="flex items-center justify-center h-full flex-col mb-10">
|
||||
<form class="flex-col justify-center w-11/12 md:w-10/12 xl:w-8/12 mt-20">
|
||||
<div class="flex-col justify-center w-11/12 md:w-10/12 xl:w-8/12 mt-20">
|
||||
<div class="flex flex-row w-full">
|
||||
<input
|
||||
type="text"
|
||||
@ -141,5 +141,5 @@
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
@ -1,6 +1,7 @@
|
||||
<script lang="js">
|
||||
import { page } from "$app/stores"
|
||||
import { onMount } from 'svelte';
|
||||
import { PUBLIC_BASE_URL } from '$env/static/public';
|
||||
|
||||
let document = null; // To store fetched document data
|
||||
let error = null; // To store any error that occurs during fetch
|
||||
@ -18,7 +19,7 @@
|
||||
|
||||
try {
|
||||
// Make the GET request to your API
|
||||
const response = await fetch(`http://localhost:3000/documents/${id}`);
|
||||
const response = await fetch(PUBLIC_BASE_URL+`/documents/${id}`);
|
||||
if (response.ok) {
|
||||
document = await response.json(); // Store document data
|
||||
} else {
|
||||
@ -33,7 +34,7 @@
|
||||
let agreeToDelete = false;
|
||||
// Function to delete a document by ID
|
||||
async function deleteDocument(id) {
|
||||
const url = `http://localhost:3000/documents/${id}`; // Update with your API base URL if different
|
||||
const url = PUBLIC_BASE_URL+`/documents/${id}`; // Update with your API base URL if different
|
||||
|
||||
// Show the confirmation popup
|
||||
alertPopup = true;
|
||||
@ -87,9 +88,7 @@ async function deleteDocument(id) {
|
||||
|
||||
{#if alertPopup}
|
||||
<!-- Full-screen overlay to darken the background -->
|
||||
<div
|
||||
class="fixed inset-0 bg-gray-600 opacity-40 z-40"
|
||||
></div>
|
||||
<div class="fixed inset-0 bg-gray-600 opacity-40 z-40"></div>
|
||||
|
||||
<!-- Centered popup -->
|
||||
<div
|
||||
@ -124,8 +123,8 @@ async function deleteDocument(id) {
|
||||
<h1 class="text-2xl">{document.title}</h1>
|
||||
{#if $page.data.session}
|
||||
<div>
|
||||
<a href="/edit?id={id}" class="bg-yellow-500 hover:bg-blue-400 border-double border-blue-100 border-2 p-3 rounded-full px-4 text-white font-roboto"><i class="fa-solid fa-pencil fa-lg"></i></a>
|
||||
<button class="bg-red-500 hover:bg-blue-400 border-double border-blue-100 border-2 p-3 rounded-full px-4 text-white font-roboto" on:click={() => { deleteDocument(documentId)}}><i class="fa-solid fa-trash fa-lg"></i></button>
|
||||
<a href="/edit?id={id}"><button class="bg-yellow-500 hover:bg-blue-400 border-double border-blue-100 border-2 p-3 rounded-full px-4 text-white font-roboto"><i class="fa-solid fa-pencil fa-lg"></i></button></a>
|
||||
<button class="bg-red-500 hover:bg-blue-400 border-double border-blue-100 border-2 p-3 rounded-full px-4 text-white font-roboto" on:click={() => { deleteDocument(id)}}><i class="fa-solid fa-trash fa-lg"></i></button>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
@ -137,15 +136,21 @@ async function deleteDocument(id) {
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="flex flex-row justify-between">
|
||||
<div class="flex flex-row justify-between text-gray-400">
|
||||
<div>
|
||||
{#if document.created_by}
|
||||
<p class="font-semibold">By: {document.created_by}</p>
|
||||
<p class="font-semibold">Created By: {document.created_by}</p>
|
||||
{#if document.edited_by}
|
||||
<p class="font-semibold">Edited By: {document.edited_by}</p>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
<div class="">
|
||||
{#if document.created_at}
|
||||
<p class="font-semibold">{new Date(document.created_at).toLocaleString()}</p>
|
||||
<p class="font-semibold">Created: {new Date(document.created_at).toLocaleString()}</p>
|
||||
{#if document.updated_at}
|
||||
<p class="font-semibold">Updated: {new Date(document.updated_at).toLocaleString()}</p>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,11 +1,12 @@
|
||||
<svelte:head>
|
||||
<title>Add</title>
|
||||
<title>Edit</title>
|
||||
</svelte:head>
|
||||
|
||||
<script>
|
||||
import { onMount, onDestroy } from 'svelte';
|
||||
import { page } from "$app/stores"
|
||||
import Tiptap from '$lib/components/Tiptap.svelte'
|
||||
import { PUBLIC_BASE_URL } from '$env/static/public';
|
||||
|
||||
let editorRef ; //This is our reference to the tiptap editor
|
||||
|
||||
@ -15,14 +16,17 @@
|
||||
let document = null; // To store fetched document data
|
||||
let error = null; // To store any error that occurs during fetch
|
||||
let documentId;
|
||||
let tags = [];
|
||||
|
||||
// Function to fetch the document by ID
|
||||
async function fetchDocumentById(id) {
|
||||
try {
|
||||
const response = await fetch(`http://localhost:3000/documents/${id}`);
|
||||
const response = await fetch(PUBLIC_BASE_URL+`/documents/${id}`);
|
||||
if (response.ok) {
|
||||
const fetchedDocument = await response.json();
|
||||
document = fetchedDocument; // Update document data
|
||||
title = document.title;
|
||||
tags = document.tags;
|
||||
console.log(document.body);
|
||||
editorRef.setHTML(document.body); // Update the editor with the HTML
|
||||
} else {
|
||||
@ -53,11 +57,11 @@
|
||||
async function save() {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const id = urlParams.get('id'); // Get the `id` from the query string
|
||||
const url = "http://localhost:3000/documents/"+id;
|
||||
const url = PUBLIC_BASE_URL+"/documents/"+id;
|
||||
|
||||
console.log("Title value:", title);
|
||||
|
||||
let created_by = $page.data.session.user?.name ?? "User";
|
||||
let edited_by = $page.data.session.user?.name ?? "User";
|
||||
|
||||
// Get the HTML from the tiptap editor
|
||||
if (editorRef) {
|
||||
@ -75,11 +79,9 @@
|
||||
title,
|
||||
body,
|
||||
tags,
|
||||
created_by
|
||||
edited_by
|
||||
};
|
||||
|
||||
console.log(payload);
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method: "PUT",
|
||||
@ -105,8 +107,6 @@
|
||||
}
|
||||
|
||||
|
||||
let tags = [];
|
||||
|
||||
// Function to remove a tag
|
||||
function removeTag(tag) {
|
||||
tags = tags.filter(t => t !== tag); // Filter out the tag from the array
|
||||
@ -114,7 +114,7 @@
|
||||
|
||||
// Function to add a tag
|
||||
function addTag() {
|
||||
const tagInput = document.querySelector('#tag');
|
||||
const tagInput = window.document.querySelector('#tag');
|
||||
const tag = tagInput.value.trim(); // Get input value and trim whitespace
|
||||
if (tag && !tags.includes(tag)) { // Ensure non-empty and no duplicates
|
||||
tags = [...tags, tag]; // Create a new array to trigger reactivity
|
||||
@ -126,7 +126,7 @@
|
||||
</script>
|
||||
|
||||
<div class="flex items-center justify-center h-full flex-col mb-10">
|
||||
<form class="flex-col justify-center w-11/12 md:w-10/12 xl:w-8/12 mt-20">
|
||||
<div class="flex-col justify-center w-11/12 md:w-10/12 xl:w-8/12 mt-20">
|
||||
<div class="flex flex-row w-full">
|
||||
<input
|
||||
type="text"
|
||||
@ -185,5 +185,5 @@
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
@ -1,6 +1,7 @@
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import { page } from "$app/stores"
|
||||
import { PUBLIC_BASE_URL } from '$env/static/public';
|
||||
|
||||
let query = false;
|
||||
let searchQuery = "";
|
||||
@ -23,7 +24,7 @@
|
||||
// Function to simulate search API call
|
||||
async function searchDocuments(query) {
|
||||
try {
|
||||
const res = await fetch(`http://localhost:3000/search?query=${query}`);
|
||||
const res = await fetch(PUBLIC_BASE_URL+`/search?query=${query}`);
|
||||
const data = await res.json();
|
||||
|
||||
if (data.length > 0) {
|
||||
@ -40,7 +41,7 @@
|
||||
// Function to fetch all documents from the API
|
||||
async function getAllDocuments() {
|
||||
try {
|
||||
const res = await fetch(`http://localhost:3000/documents`);
|
||||
const res = await fetch(PUBLIC_BASE_URL+`/documents`);
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(`Failed to fetch documents: ${res.statusText}`);
|
||||
|
Loading…
Reference in New Issue
Block a user