This commit is contained in:
2025-02-02 20:49:20 -05:00
parent bd614ef97e
commit 082626deea
2 changed files with 71 additions and 116 deletions

View File

@@ -1,9 +1,5 @@
<!-- components/content-appeals-form.html <!-- components/content-appeals-form.html
// https://bitvid.network?modal=appeals => open contentAppealsModal https://bitvid.network?modal=appeals => open contentAppealsModal
//
// Admin: npub13yarr7j6vjqjjkahd63dmr27curypehx45ucue286ac7sft27y0srnpmpe
// Form:
// Responces:
--> -->
<div <div
id="contentAppealsModal" id="contentAppealsModal"
@@ -26,11 +22,13 @@
<div <div
class="modal-content bg-gray-900 w-full max-w-[90%] lg:max-w-6xl my-0 rounded-lg overflow-hidden relative" class="modal-content bg-gray-900 w-full max-w-[90%] lg:max-w-6xl my-0 rounded-lg overflow-hidden relative"
> >
<!-- Header bar (sticky) with exit button --> <!-- Header bar (sticky) with improved title styling -->
<div <div
class="sticky top-0 bg-gradient-to-b from-black/80 to-transparent p-4 flex items-center justify-between" class="sticky top-0 bg-gradient-to-b from-black/80 to-transparent p-4 flex items-center justify-between border-b border-gray-700"
> >
<h2 class="text-2xl font-bold text-white mb-0">Content Appeals Form</h2> <h2 class="text-3xl font-extrabold text-white tracking-wide pb-2">
Content Appeals Form
</h2>
<button <button
id="closeContentAppealsModal" id="closeContentAppealsModal"
class="flex items-center justify-center w-10 h-10 rounded-full bg-black/50 hover:bg-black/70 transition-all duration-200 backdrop-blur focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-black focus:ring-blue-500" class="flex items-center justify-center w-10 h-10 rounded-full bg-black/50 hover:bg-black/70 transition-all duration-200 backdrop-blur focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-black focus:ring-blue-500"

View File

@@ -7,16 +7,24 @@
<link rel="stylesheet" href="style.css" /> <link rel="stylesheet" href="style.css" />
<style> <style>
/* Override for form page to match modal field styling */ /* Override for form page to match modal field styling */
/* Make body text white and background transparent */ /* Remove width constraints from body so our container can be full width */
body { body {
background-color: transparent; background-color: transparent;
color: #fff; color: #fff;
font-family: system-ui, -apple-system, sans-serif; font-family: system-ui, -apple-system, sans-serif;
margin: 20px; margin: 20px;
max-width: 800px; /* Removed max-width */
} }
/* Override the .container to use the full available width */
.container {
width: 100%;
max-width: 100%;
margin: 0;
padding: 0;
}
/* Card-like container for the form, similar to modal-content */ /* Card-like container for the form, similar to modal-content */
.form-container { .form-container {
background-color: #111827; /* Tailwind's bg-gray-900 */ background-color: #111827; /* Tailwind's bg-gray-900 */
@@ -24,12 +32,12 @@
border-radius: 0.5rem; border-radius: 0.5rem;
box-shadow: var(--shadow-md); box-shadow: var(--shadow-md);
} }
h1, h1,
h2 { h2 {
color: #fff; color: #fff;
} }
/* Labels in a light gray */ /* Labels in a light gray */
label { label {
display: block; display: block;
@@ -37,7 +45,7 @@
font-weight: bold; font-weight: bold;
color: #E5E7EB; /* Tailwind's text-gray-200 */ color: #E5E7EB; /* Tailwind's text-gray-200 */
} }
/* Input, textarea, and select mimic modal field styles */ /* Input, textarea, and select mimic modal field styles */
input, input,
textarea, textarea,
@@ -51,7 +59,7 @@
border-radius: 0.375rem; /* rounded-md */ border-radius: 0.375rem; /* rounded-md */
box-sizing: border-box; box-sizing: border-box;
} }
input:focus, input:focus,
textarea:focus, textarea:focus,
select:focus { select:focus {
@@ -59,7 +67,7 @@
outline: none; outline: none;
box-shadow: 0 0 0 1px #3B82F6; box-shadow: 0 0 0 1px #3B82F6;
} }
/* Button styled similarly to modal publish button */ /* Button styled similarly to modal publish button */
button { button {
padding: 0.5em 1em; padding: 0.5em 1em;
@@ -69,7 +77,7 @@
border-radius: 0.375rem; border-radius: 0.375rem;
cursor: pointer; cursor: pointer;
} }
/* Status log area */ /* Status log area */
#status { #status {
margin-top: 1em; margin-top: 1em;
@@ -91,7 +99,7 @@
.warn { .warn {
color: #FACC15; /* a yellow tone */ color: #FACC15; /* a yellow tone */
} }
/* Custom Scrollbar styling for WebKit browsers */ /* Custom Scrollbar styling for WebKit browsers */
::-webkit-scrollbar { ::-webkit-scrollbar {
width: 8px; width: 8px;
@@ -116,103 +124,60 @@
<body> <body>
<div class="container"> <div class="container">
<div class="form-container"> <div class="form-container">
<h1>bitvid Content Appeals Form</h1>
<p> <p>
If you believe your content was unfairly blocked or restricted on bitvid, If you believe your content was unfairly blocked or restricted on bitvid,
please complete this form. Appeals will be reviewed manually, and please complete this form. Appeals will be reviewed manually, and
decisions will be communicated back to you. decisions will be communicated back to you.
</p> </p>
<form id="dm-form"> <form id="dm-form">
<h2>1. User Information</h2> <h2>1. User Information</h2>
<label for="npubInput">Nostr Public Key (npub):</label> <label for="npubInput">Nostr Public Key (npub):</label>
<input <input type="text" id="npubInput" placeholder="Enter your npub" required />
type="text"
id="npubInput"
placeholder="Enter your npub"
required
/>
<label for="contactMethod">Contact Method (if applicable):</label> <label for="contactMethod">Contact Method (if applicable):</label>
<input <input type="text" id="contactMethod" placeholder="Nostr DM, email, or other" />
type="text"
id="contactMethod"
placeholder="Nostr DM, email, or other"
/>
<h2>2. Content Details</h2> <h2>2. Content Details</h2>
<label for="videoTitle">Title of the Video:</label> <label for="videoTitle">Title of the Video:</label>
<input type="text" id="videoTitle" placeholder="Enter the exact title" /> <input type="text" id="videoTitle" placeholder="Enter the exact title" />
<label for="magnetLink">Magnet Link:</label> <label for="magnetLink">Magnet Link:</label>
<input type="text" id="magnetLink" placeholder="Enter the magnet link" /> <input type="text" id="magnetLink" placeholder="Enter the magnet link" />
<label for="submissionDate">Date of Content Submission:</label> <label for="submissionDate">Date of Content Submission:</label>
<input type="date" id="submissionDate" /> <input type="date" id="submissionDate" />
<h2>3. Reason for Appeal</h2> <h2>3. Reason for Appeal</h2>
<label for="reasonBlocked" <label for="reasonBlocked">Why do you believe your content was unfairly blocked?</label>
>Why do you believe your content was unfairly blocked?</label <textarea id="reasonBlocked" rows="3" placeholder="Explain in detail"></textarea>
>
<textarea <label for="fitsGuidelines">Does your content fit within bitvid's Community Guidelines?</label>
id="reasonBlocked"
rows="3"
placeholder="Explain in detail"
></textarea>
<label for="fitsGuidelines"
>Does your content fit within bitvid's Community Guidelines?</label
>
<select id="fitsGuidelines"> <select id="fitsGuidelines">
<option value="">Select an option</option> <option value="">Select an option</option>
<option value="Yes">Yes</option> <option value="Yes">Yes</option>
<option value="No">No</option> <option value="No">No</option>
</select> </select>
<label for="guidelinesCited" <label for="guidelinesCited">If yes, which guideline(s) support your appeal?</label>
>If yes, which guideline(s) support your appeal?</label <textarea id="guidelinesCited" rows="2" placeholder="Cite the specific guidelines"></textarea>
>
<textarea <label for="editedContent">Was this content edited after being blocked?</label>
id="guidelinesCited"
rows="2"
placeholder="Cite the specific guidelines"
></textarea>
<label for="editedContent"
>Was this content edited after being blocked?</label
>
<select id="editedContent"> <select id="editedContent">
<option value="">Select an option</option> <option value="">Select an option</option>
<option value="Yes">Yes</option> <option value="Yes">Yes</option>
<option value="No">No</option> <option value="No">No</option>
</select> </select>
<label for="changesMade">If yes, what changes were made?</label> <label for="changesMade">If yes, what changes were made?</label>
<textarea <textarea id="changesMade" rows="2" placeholder="Describe the modifications"></textarea>
id="changesMade"
rows="2"
placeholder="Describe the modifications"
></textarea>
<h2>4. Additional Context</h2> <h2>4. Additional Context</h2>
<label for="misunderstanding" <label for="misunderstanding">Was there any misunderstanding or misclassification?</label>
>Was there any misunderstanding or misclassification?</label <textarea id="misunderstanding" rows="2" placeholder="Provide context"></textarea>
>
<textarea <label for="externalReferences">Are there external references that validate your appeal?</label>
id="misunderstanding" <textarea id="externalReferences" rows="2" placeholder="Links, citations, or additional info"></textarea>
rows="2"
placeholder="Provide context"
></textarea>
<label for="externalReferences"
>Are there external references that validate your appeal?</label
>
<textarea
id="externalReferences"
rows="2"
placeholder="Links, citations, or additional info"
></textarea>
<h2>5. Declaration</h2> <h2>5. Declaration</h2>
<p> <p>
By submitting this appeal, you confirm that: By submitting this appeal, you confirm that:
@@ -222,17 +187,15 @@
</p> </p>
<label for="signature">Signature (Digital or Written):</label> <label for="signature">Signature (Digital or Written):</label>
<input type="text" id="signature" placeholder="Your signature" /> <input type="text" id="signature" placeholder="Your signature" />
<label for="declarationDate">Date:</label> <label for="declarationDate">Date:</label>
<input type="date" id="declarationDate" /> <input type="date" id="declarationDate" />
<button type="submit">Submit Appeal</button> <button type="submit">Submit Appeal</button>
</form> </form>
<div id="status"></div> <div id="status"></div>
</div> </div>
</div> </div>
<script> <script>
document.addEventListener("DOMContentLoaded", () => { document.addEventListener("DOMContentLoaded", () => {
// Logging functions for both on-page and console output. // Logging functions for both on-page and console output.
@@ -249,12 +212,10 @@
function clear() { function clear() {
document.getElementById("status").innerHTML = ""; document.getElementById("status").innerHTML = "";
} }
if (!window.NostrTools) { if (!window.NostrTools) {
log("NostrTools not loaded. Check console or ad-blockers.", "error"); log("NostrTools not loaded. Check console or ad-blockers.", "error");
return; return;
} }
const { const {
generateSecretKey, generateSecretKey,
getPublicKey, getPublicKey,
@@ -264,19 +225,15 @@
SimplePool, SimplePool,
Relay, Relay,
} = window.NostrTools; } = window.NostrTools;
const RELAYS = [ const RELAYS = [
"wss://relay.snort.social", "wss://relay.snort.social",
"wss://relay.damus.io", "wss://relay.damus.io",
"wss://relay.primal.net", "wss://relay.primal.net",
]; ];
const pool = new SimplePool(); const pool = new SimplePool();
document.getElementById("dm-form").addEventListener("submit", async (ev) => { document.getElementById("dm-form").addEventListener("submit", async (ev) => {
ev.preventDefault(); ev.preventDefault();
clear(); clear();
try { try {
// Retrieve user input. // Retrieve user input.
const npub = document.getElementById("npubInput").value.trim(); const npub = document.getElementById("npubInput").value.trim();
@@ -296,20 +253,20 @@
const externalReferences = document.getElementById("externalReferences").value.trim(); const externalReferences = document.getElementById("externalReferences").value.trim();
const signature = document.getElementById("signature").value.trim(); const signature = document.getElementById("signature").value.trim();
const declarationDate = document.getElementById("declarationDate").value.trim(); const declarationDate = document.getElementById("declarationDate").value.trim();
// Construct the appeal content. // Construct the appeal content.
const appealContent = ` const appealContent = `
# **bitvid Content Appeals Form** # **bitvid Content Appeals Form**
**1. User Information** **1. User Information**
- **Nostr Public Key (npub):** ${npub} - **Nostr Public Key (npub):** ${npub}
- **Contact Method:** ${contactMethod || "N/A"} - **Contact Method:** ${contactMethod || "N/A"}
**2. Content Details** **2. Content Details**
- **Title of the Video:** ${videoTitle} - **Title of the Video:** ${videoTitle}
- **Magnet Link:** ${magnetLink} - **Magnet Link:** ${magnetLink}
- **Date of Content Submission:** ${submissionDate} - **Date of Content Submission:** ${submissionDate}
**3. Reason for Appeal** **3. Reason for Appeal**
- **Why do you believe your content was unfairly blocked?** - **Why do you believe your content was unfairly blocked?**
${reasonBlocked} ${reasonBlocked}
@@ -321,31 +278,31 @@
${editedContent} ${editedContent}
- **If yes, what changes were made?** - **If yes, what changes were made?**
${changesMade} ${changesMade}
**4. Additional Context** **4. Additional Context**
- **Was there any misunderstanding or misclassification?** - **Was there any misunderstanding or misclassification?**
${misunderstanding} ${misunderstanding}
- **Are there external references that validate your appeal?** - **Are there external references that validate your appeal?**
${externalReferences} ${externalReferences}
**5. Declaration** **5. Declaration**
By submitting this appeal, you confirm that: By submitting this appeal, you confirm that:
- You are the original creator or an authorized representative of the content. - You are the original creator or an authorized representative of the content.
- Your appeal is submitted in good faith and aligns with bitvids policies. - Your appeal is submitted in good faith and aligns with bitvids policies.
- You understand that final decisions are at the discretion of bitvids moderation process. - You understand that final decisions are at the discretion of bitvids moderation process.
**Signature (Digital or Written):** ${signature} **Signature (Digital or Written):** ${signature}
**Date:** ${declarationDate} **Date:** ${declarationDate}
--- ---
**Processing Time:** Appeals will be reviewed within **7-14 days**. If additional information is required, you will be contacted via your provided contact method. **Processing Time:** Appeals will be reviewed within **7-14 days**. If additional information is required, you will be contacted via your provided contact method.
For further questions, reach out through bitvids Nostr support channels. For further questions, reach out through bitvids Nostr support channels.
`.trim(); `.trim();
log("[DEBUG] Constructed appeal content:\n" + appealContent); log("[DEBUG] Constructed appeal content:\n" + appealContent);
// Decode the target npub to get the public key. // Decode the target npub to get the public key.
log("Decoding target npub..."); log("Decoding target npub...");
const decoded = nip19.decode(npub); const decoded = nip19.decode(npub);
@@ -355,19 +312,19 @@ For further questions, reach out through bitvids Nostr support channels.
} }
const targetPubHex = decoded.data; const targetPubHex = decoded.data;
log("Target pubkey: " + targetPubHex.slice(0, 16) + "..."); log("Target pubkey: " + targetPubHex.slice(0, 16) + "...");
// Generate an ephemeral key pair. // Generate an ephemeral key pair.
log("Generating ephemeral key..."); log("Generating ephemeral key...");
const ephemeralPriv = generateSecretKey(); const ephemeralPriv = generateSecretKey();
const ephemeralPubHex = getPublicKey(ephemeralPriv); const ephemeralPubHex = getPublicKey(ephemeralPriv);
log("Ephemeral pubkey: " + ephemeralPubHex.slice(0, 16) + "..."); log("Ephemeral pubkey: " + ephemeralPubHex.slice(0, 16) + "...");
// Encrypt the appeal content. // Encrypt the appeal content.
log("Encrypting appeal content (nip04)..."); log("Encrypting appeal content (nip04)...");
const ciphertext = await nip04.encrypt(ephemeralPriv, targetPubHex, appealContent); const ciphertext = await nip04.encrypt(ephemeralPriv, targetPubHex, appealContent);
log("[DEBUG] Ciphertext: " + ciphertext); log("[DEBUG] Ciphertext: " + ciphertext);
log("Encryption done."); log("Encryption done.");
// Build the event template. // Build the event template.
const now = Math.floor(Date.now() / 1000); const now = Math.floor(Date.now() / 1000);
const eventTemplate = { const eventTemplate = {
@@ -377,16 +334,16 @@ For further questions, reach out through bitvids Nostr support channels.
content: ciphertext, content: ciphertext,
}; };
log("[DEBUG] Event template before finalizing: " + JSON.stringify(eventTemplate)); log("[DEBUG] Event template before finalizing: " + JSON.stringify(eventTemplate));
// Finalize the event. // Finalize the event.
const event = finalizeEvent(eventTemplate, ephemeralPriv); const event = finalizeEvent(eventTemplate, ephemeralPriv);
log("[DEBUG] Final event: " + JSON.stringify(event)); log("[DEBUG] Final event: " + JSON.stringify(event));
// Publish the event to all relays. // Publish the event to all relays.
log("Publishing the appeal to relays..."); log("Publishing the appeal to relays...");
await Promise.any(pool.publish(RELAYS, event)); await Promise.any(pool.publish(RELAYS, event));
log("At least one relay accepted the event.", "success"); log("At least one relay accepted the event.", "success");
// Subscribe to each relay. // Subscribe to each relay.
for (const url of RELAYS) { for (const url of RELAYS) {
log("Connecting to " + url + " for subscription..."); log("Connecting to " + url + " for subscription...");
@@ -402,7 +359,7 @@ For further questions, reach out through bitvids Nostr support channels.
}, },
}); });
} }
log("Done. If the logs show that at least one relay accepted the event and the appeal was found in storage, a moderator will review your appeal within 7-14 days."); log("Done. If the logs show that at least one relay accepted the event and the appeal was found in storage, a moderator will review your appeal within 7-14 days.");
} catch (err) { } catch (err) {
log("Error: " + err.message, "error"); log("Error: " + err.message, "error");