add a way for a user to get their email
This commit is contained in:
parent
44e3f6e7ff
commit
2b84b9c433
2 changed files with 318 additions and 33 deletions
|
@ -6,11 +6,11 @@ import { toast } from 'react-hot-toast';
|
|||
|
||||
export default function EmailRequestSettings() {
|
||||
const auth = Authentication.getInstance();
|
||||
const update = Update.getInstance();
|
||||
const [user, setUser] = useState<User | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [requesting, setRequesting] = useState(false);
|
||||
const [isOfficer, setIsOfficer] = useState(false);
|
||||
const [createdEmail, setCreatedEmail] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const loadUserData = async () => {
|
||||
|
@ -52,20 +52,38 @@ export default function EmailRequestSettings() {
|
|||
try {
|
||||
setRequesting(true);
|
||||
|
||||
// Update the user record to mark email as requested
|
||||
const pb = auth.getPocketBase();
|
||||
await pb.collection(Collections.USERS).update(user.id, {
|
||||
requested_email: true
|
||||
// Call the API to create the email account
|
||||
const response = await fetch('/api/create-ieee-email', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
userId: user.id,
|
||||
name: user.name,
|
||||
email: user.email
|
||||
})
|
||||
});
|
||||
|
||||
// Refresh user data
|
||||
const updatedUser = auth.getCurrentUser();
|
||||
setUser(updatedUser);
|
||||
const result = await response.json();
|
||||
|
||||
toast.success('Email request submitted successfully! Our team will process your request soon.');
|
||||
if (response.ok && result.success) {
|
||||
// Email created successfully
|
||||
setCreatedEmail(result.data.ieeeEmail);
|
||||
|
||||
// Update the user record to mark email as requested
|
||||
const pb = auth.getPocketBase();
|
||||
await pb.collection(Collections.USERS).update(user.id, {
|
||||
requested_email: true
|
||||
});
|
||||
|
||||
toast.success('IEEE email created successfully! Check your email for login details.');
|
||||
} else {
|
||||
toast.error(result.message || 'Failed to create email. Please contact the webmaster for assistance.');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error requesting email:', error);
|
||||
toast.error('Failed to submit email request. Please try again later.');
|
||||
toast.error('Failed to create email. Please try again later.');
|
||||
} finally {
|
||||
setRequesting(false);
|
||||
}
|
||||
|
@ -81,33 +99,38 @@ export default function EmailRequestSettings() {
|
|||
|
||||
if (!isOfficer) {
|
||||
return (
|
||||
<div className="alert alert-info">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" className="stroke-current shrink-0 w-6 h-6"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
|
||||
<span>IEEE email addresses are only available to officers. If you are an officer and don't see the option to request an email, please contact the webmaster.</span>
|
||||
<div className="p-4 bg-base-200 rounded-lg">
|
||||
<p>IEEE email addresses are only available to officers. If you are an officer and don't see the option to request an email, please contact the webmaster.</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (user?.requested_email) {
|
||||
if (user?.requested_email || createdEmail) {
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="alert alert-success">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="stroke-current shrink-0 h-6 w-6" fill="none" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
|
||||
<span>You have requested an IEEE email address. Our team is processing your request.</span>
|
||||
</div>
|
||||
<div className="p-4 bg-base-200 rounded-lg">
|
||||
<h3 className="font-bold text-lg mb-2">
|
||||
{createdEmail ? 'Your IEEE Email Address' : 'Email Request Status'}
|
||||
</h3>
|
||||
|
||||
<div className="card bg-base-200 p-4">
|
||||
<h3 className="font-bold text-lg mb-2">What happens next?</h3>
|
||||
<ol className="list-decimal list-inside space-y-2">
|
||||
<li>Our webmaster will create your email address (typically firstname.lastname@ieeeucsd.org)</li>
|
||||
<li>You'll receive an email with your credentials and setup instructions</li>
|
||||
<li>You can use this email for IEEE-related communications</li>
|
||||
</ol>
|
||||
</div>
|
||||
{createdEmail && (
|
||||
<div className="mb-4">
|
||||
<p className="text-xl font-mono bg-base-100 p-2 rounded">{createdEmail}</p>
|
||||
<p className="mt-2 text-sm">Check your personal email for login instructions.</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="alert alert-info">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" className="stroke-current shrink-0 w-6 h-6"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
|
||||
<span>If you have any questions or need help with your IEEE email, please contact <a href="mailto:webmaster@ieeeucsd.org" className="underline">webmaster@ieeeucsd.org</a></span>
|
||||
<div className="mb-4">
|
||||
<h4 className="font-semibold mb-1">Access Your Email</h4>
|
||||
<ul className="list-disc list-inside space-y-1">
|
||||
<li>Webmail: <a href="https://heracles.mxrouting.net:2096/" target="_blank" rel="noopener noreferrer" className="link link-primary">https://heracles.mxrouting.net:2096/</a></li>
|
||||
<li>IMAP/SMTP settings: <a href="https://mxroute.com/setup/" target="_blank" rel="noopener noreferrer" className="link link-primary">https://mxroute.com/setup/</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<p className="text-sm">
|
||||
If you have any questions or need help with your IEEE email, please contact <a href="mailto:webmaster@ieeeucsd.org" className="underline">webmaster@ieeeucsd.org</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -119,7 +142,7 @@ export default function EmailRequestSettings() {
|
|||
As an IEEE officer, you're eligible for an official IEEE UCSD email address. This email can be used for all IEEE-related communications and provides a professional identity when representing the organization.
|
||||
</p>
|
||||
|
||||
<div className="card bg-base-200 p-4">
|
||||
<div className="p-4 bg-base-200 rounded-lg">
|
||||
<h3 className="font-bold text-lg mb-2">Benefits of an IEEE email:</h3>
|
||||
<ul className="list-disc list-inside space-y-1">
|
||||
<li>Professional communication with sponsors and partners</li>
|
||||
|
@ -137,16 +160,16 @@ export default function EmailRequestSettings() {
|
|||
{requesting ? (
|
||||
<>
|
||||
<span className="loading loading-spinner loading-sm"></span>
|
||||
Processing...
|
||||
Creating Email...
|
||||
</>
|
||||
) : (
|
||||
'Request IEEE Email Address'
|
||||
'Create IEEE Email Address'
|
||||
)}
|
||||
</button>
|
||||
|
||||
<div className="text-xs opacity-70">
|
||||
<p>By requesting an email, you agree to use it responsibly and in accordance with IEEE UCSD policies.</p>
|
||||
<p>Email addresses are typically in the format firstname.lastname@ieeeucsd.org</p>
|
||||
<p>Your email address will be based on your current email username.</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
262
src/pages/api/create-ieee-email.ts
Normal file
262
src/pages/api/create-ieee-email.ts
Normal file
|
@ -0,0 +1,262 @@
|
|||
import type { APIRoute } from "astro";
|
||||
|
||||
export const POST: APIRoute = async ({ request }) => {
|
||||
try {
|
||||
const { userId, name, email } = await request.json();
|
||||
|
||||
if (!userId || !name || !email) {
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
message: "Missing required parameters",
|
||||
}),
|
||||
{
|
||||
status: 400,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// Extract username from email (everything before the @ symbol)
|
||||
const emailUsername = email.split("@")[0].toLowerCase();
|
||||
|
||||
// Remove any special characters that might cause issues
|
||||
const cleanUsername = emailUsername.replace(/[^a-z0-9]/g, "");
|
||||
|
||||
// Generate a secure random password
|
||||
const password = generateSecurePassword();
|
||||
|
||||
// MXRoute DirectAdmin API credentials from environment variables
|
||||
const loginKey = import.meta.env.MXROUTE_LOGIN_KEY;
|
||||
const serverLogin = import.meta.env.MXROUTE_SERVER_LOGIN;
|
||||
const serverUrl = import.meta.env.MXROUTE_SERVER_URL;
|
||||
const emailQuota = import.meta.env.MXROUTE_EMAIL_QUOTA;
|
||||
const emailOutboundLimit = import.meta.env.MXROUTE_EMAIL_OUTBOUND_LIMIT;
|
||||
const emailDomain = import.meta.env.MXROUTE_EMAIL_DOMAIN;
|
||||
|
||||
if (!loginKey || !serverLogin || !serverUrl || !emailDomain) {
|
||||
throw new Error("Missing MXRoute configuration");
|
||||
}
|
||||
|
||||
// DirectAdmin API endpoint for creating email accounts
|
||||
// According to the documentation: https://docs.directadmin.com/developer/api/legacy-api.html
|
||||
let baseUrl = serverUrl;
|
||||
|
||||
// If the URL contains a specific command, extract just the base URL
|
||||
if (baseUrl.includes("/CMD_")) {
|
||||
baseUrl = baseUrl.split("/CMD_")[0];
|
||||
}
|
||||
|
||||
// Make sure there's no trailing slash
|
||||
baseUrl = baseUrl.replace(/\/$/, "");
|
||||
|
||||
// Construct the email POP API URL
|
||||
const emailApiUrl = `${baseUrl}/CMD_API_EMAIL_POP`;
|
||||
|
||||
console.log(`Creating email account: ${cleanUsername}@${emailDomain}`);
|
||||
console.log(`DirectAdmin API URL: ${emailApiUrl}`);
|
||||
|
||||
// Create the email account via DirectAdmin API
|
||||
// According to DirectAdmin legacy API docs:
|
||||
// https://docs.directadmin.com/developer/api/legacy-api.html
|
||||
const formData = new URLSearchParams();
|
||||
formData.append("action", "create");
|
||||
formData.append("domain", emailDomain);
|
||||
formData.append("user", cleanUsername); // DirectAdmin uses 'user' for POP accounts
|
||||
formData.append("passwd", password);
|
||||
formData.append("passwd2", password);
|
||||
formData.append("quota", emailQuota || "200");
|
||||
formData.append("limit", emailOutboundLimit || "9600");
|
||||
|
||||
// Log the form data being sent
|
||||
console.log("Form data:");
|
||||
formData.forEach((value, key) => {
|
||||
console.log(` ${key}: ${value}`);
|
||||
});
|
||||
|
||||
const response = await fetch(emailApiUrl, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
Authorization: `Basic ${Buffer.from(`${serverLogin}:${loginKey}`).toString("base64")}`,
|
||||
},
|
||||
body: formData,
|
||||
});
|
||||
|
||||
const responseText = await response.text();
|
||||
console.log(`DirectAdmin response: ${responseText}`);
|
||||
|
||||
// DirectAdmin API returns "error=1" in the response text for errors
|
||||
if (responseText.includes("error=1") || !response.ok) {
|
||||
console.error("Error creating email account:", responseText);
|
||||
|
||||
// Parse the error details if possible
|
||||
let errorMessage = "Failed to create email account";
|
||||
try {
|
||||
const errorParams = new URLSearchParams(responseText);
|
||||
if (errorParams.has("text")) {
|
||||
errorMessage = decodeURIComponent(errorParams.get("text") || "");
|
||||
}
|
||||
if (errorParams.has("details")) {
|
||||
const details = decodeURIComponent(errorParams.get("details") || "");
|
||||
errorMessage += `: ${details.replace(/<br>/g, " ")}`;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Error parsing DirectAdmin error response:", e);
|
||||
}
|
||||
|
||||
// If the error is because the email already exists
|
||||
if (responseText.includes("already exists")) {
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
message: `Email address ${cleanUsername}@${emailDomain} already exists. Please contact the webmaster for assistance.`,
|
||||
}),
|
||||
{
|
||||
status: 409,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
// Send notification email to the user with their new email credentials
|
||||
await sendCredentialsEmail(
|
||||
email,
|
||||
`${cleanUsername}@${emailDomain}`,
|
||||
password,
|
||||
);
|
||||
|
||||
// Send notification to webmaster
|
||||
await sendWebmasterNotification(
|
||||
userId,
|
||||
name,
|
||||
email,
|
||||
`${cleanUsername}@${emailDomain}`,
|
||||
);
|
||||
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
data: {
|
||||
ieeeEmail: `${cleanUsername}@${emailDomain}`,
|
||||
message:
|
||||
"Email account created successfully. Check your email for login details.",
|
||||
},
|
||||
}),
|
||||
{
|
||||
status: 200,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("Error in create-ieee-email:", error);
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
message: error instanceof Error ? error.message : "An error occurred",
|
||||
}),
|
||||
{
|
||||
status: 500,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// Generate a secure random password
|
||||
function generateSecurePassword(length = 16) {
|
||||
const charset =
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_+";
|
||||
let password = "";
|
||||
|
||||
// Ensure at least one character from each category
|
||||
password += charset.substring(0, 26).charAt(Math.floor(Math.random() * 26)); // lowercase
|
||||
password += charset.substring(26, 52).charAt(Math.floor(Math.random() * 26)); // uppercase
|
||||
password += charset.substring(52, 62).charAt(Math.floor(Math.random() * 10)); // number
|
||||
password += charset
|
||||
.substring(62)
|
||||
.charAt(Math.floor(Math.random() * (charset.length - 62))); // special
|
||||
|
||||
// Fill the rest randomly
|
||||
for (let i = 4; i < length; i++) {
|
||||
password += charset.charAt(Math.floor(Math.random() * charset.length));
|
||||
}
|
||||
|
||||
// Shuffle the password
|
||||
return password
|
||||
.split("")
|
||||
.sort(() => 0.5 - Math.random())
|
||||
.join("");
|
||||
}
|
||||
|
||||
// Send email with credentials to the user
|
||||
async function sendCredentialsEmail(
|
||||
userEmail: string,
|
||||
ieeeEmail: string,
|
||||
password: string,
|
||||
) {
|
||||
// In a real implementation, you would use an email service like SendGrid, Mailgun, etc.
|
||||
// For now, we'll just log the email that would be sent
|
||||
console.log(`
|
||||
To: ${userEmail}
|
||||
Subject: Your IEEE UCSD Email Account
|
||||
|
||||
Hello,
|
||||
|
||||
Your IEEE UCSD email account has been created:
|
||||
|
||||
Email address: ${ieeeEmail}
|
||||
Password: ${password}
|
||||
|
||||
You can access your email through:
|
||||
- Webmail: https://heracles.mxrouting.net:2096/
|
||||
- IMAP/SMTP settings can be found at: https://mxroute.com/setup/
|
||||
|
||||
Please change your password after your first login.
|
||||
|
||||
If you have any questions, please contact webmaster@ieeeucsd.org.
|
||||
|
||||
Best regards,
|
||||
IEEE UCSD Web Team
|
||||
`);
|
||||
|
||||
// In a production environment, replace with actual email sending code
|
||||
return true;
|
||||
}
|
||||
|
||||
// Send notification to webmaster
|
||||
async function sendWebmasterNotification(
|
||||
userId: string,
|
||||
name: string,
|
||||
email: string,
|
||||
ieeeEmail: string,
|
||||
) {
|
||||
// In a real implementation, you would use an email service
|
||||
console.log(`
|
||||
To: webmaster@ieeeucsd.org
|
||||
Subject: New IEEE Email Account Created
|
||||
|
||||
A new IEEE email account has been created:
|
||||
|
||||
User ID: ${userId}
|
||||
Name: ${name}
|
||||
Personal Email: ${email}
|
||||
IEEE Email: ${ieeeEmail}
|
||||
|
||||
This is an automated notification.
|
||||
`);
|
||||
|
||||
// In a production environment, replace with actual email sending code
|
||||
return true;
|
||||
}
|
Loading…
Reference in a new issue