diff --git a/app/routes/links_routes.py b/app/routes/links_routes.py index 90ca1bd..984ccd8 100644 --- a/app/routes/links_routes.py +++ b/app/routes/links_routes.py @@ -61,7 +61,7 @@ async def create_link( return {"link": link_path, "expire_date": new_link.expire_date} -@router.delete("/{link}", summary="Delete a link") +@router.delete("/{link}", summary="Delete a link and all associated logs") async def delete_link( link: Annotated[str, Path(title="Link to delete")], current_user: Annotated[User, Depends(get_current_user)], @@ -126,9 +126,13 @@ async def get_link_logs( return logs -@router.delete("/{link}/logs", summary="Delete logs associated with a link") -async def delete_link_logs( - link: Annotated[str, Path(title="Link to delete logs for")], +@router.delete( + "/{link}/logs/{log_id}", + summary="Delete a specific log associated with a link", +) +async def delete_single_log( + link: Annotated[str, Path(title="Link associated with the log to delete")], + log_id: Annotated[int, Path(title="Log ID to delete")], current_user: Annotated[User, Depends(get_current_user)], db=Depends(get_db), ): @@ -148,10 +152,13 @@ async def delete_link_logs( detail="Link not associated with your account", ) - # Get all of the logs - logs = db.query(Log).filter(Log.link == link.link).all() - for log in logs: - db.delete(log) + # Get the log and delete it + log = db.query(Log).filter(Log.id == log_id).first() + if not log: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, detail="Log not found" + ) + db.delete(log) db.commit() return status.HTTP_204_NO_CONTENT diff --git a/app/templates/dashboard.html b/app/templates/dashboard.html index c65b62b..0a383af 100644 --- a/app/templates/dashboard.html +++ b/app/templates/dashboard.html @@ -4,46 +4,19 @@ LinkLogger | Dashboard + +
- +
- - - - + + + + - - - - - - - -
LinkVisitsRedirectExpire DateLinkVisitsRedirectExpire Date
@@ -58,68 +31,62 @@ } div { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - text-align: center; - font-size: 25px; - color: #ccc; + display: flex; + justify-content: center; + margin-top: 100px; } table { - border-collapse: collapse; - background-color: #333; + margin: 20px 0 20px 0; + text-align: center; + font-size: 25px; + width: 1250px; color: #ccc; - } - - th, td { - border: 1px solid #ccc; - padding: 10px; - } - - th { - background-color: #444; - } - - tr:nth-child(even) { - background-color: #444; - } - - tr:nth-child(odd) { - background-color: #333; - } - - .log-table-row { - display: none; - } - - .log-table-row td { - padding: 0; - } - - .log-table-row table { - width: 100%; border-collapse: collapse; + overflow: hidden; } - .log-table-row th, .log-table-row td { - border: 1px solid #ccc; + table th { + background-color: #415eac; + padding: 10px; + border: 2px solid #ccc; + } + + .link-table-row { + border: 2px solid #ccc; + } + + table td { padding: 10px; } - .log-table-row th { - background-color: #444; + .link-table-row td { + padding: 20px; } - .log-table-row tr:nth-child(even) { - background-color: #444; + .log-table-row table td { + background-color: #3b4148; + padding: 10px; } - .log-table-row tr:nth-child(odd) { - background-color: #333; + .log-table-row table tr { + border: 2px solid #ccc; } + .link-button { + background-color: #3b4148; + color: #ccc; + border: none; + padding: 10px; + cursor: pointer; + font-size: 25px; + border-radius: 5px; + } + + .fa-trash:hover { + color: rgb(238, 86, 86); + cursor: pointer; + } @@ -146,24 +113,25 @@ function createRow(index, link, logs) { // Create the sub-table with the logs let subTable = ` - +
- - - - - + + + + + `; // Loop through the logs and create a row for each one logs.forEach((log, index) => { let row = ` - + + `; subTable += row; @@ -184,16 +152,16 @@ // Create the HTML for the row with sub-table let row = ` - + - - + @@ -221,26 +189,41 @@ }); } - function hideLogTables() { - let tables = document.querySelectorAll('table tr table'); - tables.forEach(table => { - table.style.display = 'none'; + // hideLogRows to all log-table-rows + function hideLogRows() { + let logTRs = document.querySelectorAll('.log-table-row'); + logTRs.forEach(row => { + row.style.display = 'none'; }); } - getData(); - hideLogTables(); - - // Add event listener to each element with the class of link-button + // Add event listener to all link buttons document.addEventListener('click', (event) => { if (event.target.classList.contains('link-button')) { let id = event.target.id; - let table = document.getElementById(`${id}-log`); - if (table.style.display === 'none') { - table.style.display = 'table-row'; + let logTR = document.getElementById(`${id}-logTR`); + if (logTR.style.display === 'none') { + hideLogRows(); + logTR.style.display = 'table-row'; } else { - table.style.display = 'none'; + logTR.style.display = 'none'; } } }); + + // Add an event listen to all trash bins + document.addEventListener('click', (event) => { + if (event.target.classList.contains('fa-trash')) { + let id = event.target.id; + let link = id.split('/')[1]; + let logId = id.split('/')[0]; + fetch(`/api/links/${link}/logs/${logId}`, { + method: 'DELETE' + }); + let logRow = document.getElementById(`${logId}-log`) + logRow.remove(); + } + }); + + getData(); \ No newline at end of file
IDTimestampIPLocationISPIDTimestampIPLocationISP
${logs.length - index} ${log.timestamp} ${log.ip} ${log.location} ${log.isp}
+