Reubensubmissions.ts28 matches
1import { Hono } from "https://esm.sh/hono@3.11.7";
2import type { SubmitExamRequest, ApiResponse, User, ExamSubmission, Question, GradeResult } from "../../shared/types.ts";
3import * as db from "../database/queries.ts";
4import { requireAuth, requireInstructor } from "./auth.ts";
6566if (isNaN(examId)) {
67return c.json<ApiResponse>({ success: false, error: "Invalid exam ID" }, 400);
68}
6970if (user.role !== 'student') {
71return c.json<ApiResponse>({ success: false, error: "Only students can submit exams" }, 403);
72}
7375const exam = await db.getExamById(examId);
76if (!exam) {
77return c.json<ApiResponse>({ success: false, error: "Exam not found" }, 404);
78}
7980if (!exam.is_published) {
81return c.json<ApiResponse>({ success: false, error: "Exam is not published" }, 403);
82}
8385const enrolled = await db.isUserEnrolled(user.id, exam.course_id);
86if (!enrolled) {
87return c.json<ApiResponse>({ success: false, error: "Not enrolled in this course" }, 403);
88}
8991const existingSubmission = await db.getSubmission(examId, user.id);
92if (existingSubmission) {
93return c.json<ApiResponse>({ success: false, error: "Exam already submitted" }, 400);
94}
9599const now = new Date();
100if (now > dueDate) {
101return c.json<ApiResponse>({ success: false, error: "Exam deadline has passed" }, 400);
102}
103}
137}
138139return c.json<ApiResponse<{ submission: ExamSubmission; gradeResults: GradeResult[] }>>({
140success: true,
141data: { submission, gradeResults }
143} catch (error) {
144console.error("Submit exam error:", error);
145return c.json<ApiResponse>({ success: false, error: "Failed to submit exam" }, 500);
146}
147});
154155if (isNaN(examId)) {
156return c.json<ApiResponse>({ success: false, error: "Invalid exam ID" }, 400);
157}
158160const exam = await db.getExamById(examId);
161if (!exam) {
162return c.json<ApiResponse>({ success: false, error: "Exam not found" }, 404);
163}
164165const course = await db.getCourseById(exam.course_id);
166if (!course || course.instructor_id !== user.id) {
167return c.json<ApiResponse>({ success: false, error: "Access denied" }, 403);
168}
169170const submissionList = await db.getExamSubmissions(examId);
171return c.json<ApiResponse>({ success: true, data: submissionList });
172} catch (error) {
173console.error("Get submissions error:", error);
174return c.json<ApiResponse>({ success: false, error: "Failed to get submissions" }, 500);
175}
176});
183184if (isNaN(submissionId)) {
185return c.json<ApiResponse>({ success: false, error: "Invalid submission ID" }, 400);
186}
187197198if (result.rows.length === 0) {
199return c.json<ApiResponse>({ success: false, error: "Submission not found" }, 404);
200}
201206if (user.role === 'student') {
207if (submissionData.user_id !== user.id) {
208return c.json<ApiResponse>({ success: false, error: "Access denied" }, 403);
209}
210} else if (user.role === 'instructor') {
211const course = await db.getCourseById(submissionData.course_id);
212if (!course || course.instructor_id !== user.id) {
213return c.json<ApiResponse>({ success: false, error: "Access denied" }, 403);
214}
215}
218const questions = await db.getExamQuestions(submissionData.exam_id);
219220return c.json<ApiResponse>({
221success: true,
222data: {
227} catch (error) {
228console.error("Get submission error:", error);
229return c.json<ApiResponse>({ success: false, error: "Failed to get submission" }, 500);
230}
231});
239240if (isNaN(submissionId)) {
241return c.json<ApiResponse>({ success: false, error: "Invalid submission ID" }, 400);
242}
243244if (typeof score !== 'number' || score < 0) {
245return c.json<ApiResponse>({ success: false, error: "Invalid score" }, 400);
246}
247256257if (result.rows.length === 0) {
258return c.json<ApiResponse>({ success: false, error: "Submission not found" }, 404);
259}
260262const course = await db.getCourseById(submissionData.course_id);
263if (!course || course.instructor_id !== user.id) {
264return c.json<ApiResponse>({ success: false, error: "Access denied" }, 403);
265}
266267// Validate score doesn't exceed max
268if (score > submissionData.max_score) {
269return c.json<ApiResponse>({
270success: false,
271error: `Score cannot exceed maximum of ${submissionData.max_score}`
274275await db.updateSubmissionScore(submissionId, score, user.id);
276return c.json<ApiResponse>({ success: true, data: { message: "Score updated successfully" } });
277} catch (error) {
278console.error("Grade submission error:", error);
279return c.json<ApiResponse>({ success: false, error: "Failed to update score" }, 500);
280}
281});
2import { readFile, serveFile } from "https://esm.town/v/std/utils@85-main/index.ts";
3import { londonAttractions } from "./data/attractions.ts";
4import { ApiResponse, Attraction } from "../shared/types.ts";
56const app = new Hono();
15app.get("/shared/*", c => serveFile(c.req.path, import.meta.url));
1617// API Routes
18app.get("/api/attractions", async (c) => {
19const response: ApiResponse<Attraction[]> = {
20success: true,
21data: londonAttractions
24});
2526app.get("/api/attractions/:id", async (c) => {
27const id = c.req.param("id");
28const attraction = londonAttractions.find(a => a.id === id);
29
30if (!attraction) {
31const response: ApiResponse<null> = {
32success: false,
33error: "Attraction not found"
36}
37
38const response: ApiResponse<Attraction> = {
39success: true,
40data: attraction
43});
4445app.get("/api/attractions/category/:category", async (c) => {
46const category = c.req.param("category");
47const filteredAttractions = londonAttractions.filter(a => a.category === category);
48
49const response: ApiResponse<Attraction[]> = {
50success: true,
51data: filteredAttractions
1import { Hono } from "https://esm.sh/hono@3.11.7";
2import type { CreateExamRequest, ApiResponse, Exam, Question, User, ExamAttempt } from "../../shared/types.ts";
3import * as db from "../database/queries.ts";
4import { requireAuth, requireInstructor } from "./auth.ts";
1314if (isNaN(courseId)) {
15return c.json<ApiResponse>({ success: false, error: "Invalid course ID" }, 400);
16}
1719const course = await db.getCourseById(courseId);
20if (!course) {
21return c.json<ApiResponse>({ success: false, error: "Course not found" }, 404);
22}
2325const enrolled = await db.isUserEnrolled(user.id, courseId);
26if (!enrolled) {
27return c.json<ApiResponse>({ success: false, error: "Not enrolled in this course" }, 403);
28}
29} else if (user.role === 'instructor' && course.instructor_id !== user.id) {
30return c.json<ApiResponse>({ success: false, error: "Access denied" }, 403);
31}
3238: examList;
3940return c.json<ApiResponse<Exam[]>>({ success: true, data: filteredExams });
41} catch (error) {
42console.error("Get exams error:", error);
43return c.json<ApiResponse>({ success: false, error: "Failed to get exams" }, 500);
44}
45});
5354if (isNaN(courseId)) {
55return c.json<ApiResponse>({ success: false, error: "Invalid course ID" }, 400);
56}
5759const course = await db.getCourseById(courseId);
60if (!course || course.instructor_id !== user.id) {
61return c.json<ApiResponse>({ success: false, error: "Access denied" }, 403);
62}
636566if (!title || !description || !duration_minutes || !questions || questions.length === 0) {
67return c.json<ApiResponse>({ success: false, error: "All fields are required and at least one question must be provided" }, 400);
68}
6994exam.total_points = totalPoints;
9596return c.json<ApiResponse<{ exam: Exam; questions: Question[] }>>({
97success: true,
98data: { exam, questions: createdQuestions }
100} catch (error) {
101console.error("Create exam error:", error);
102return c.json<ApiResponse>({ success: false, error: "Failed to create exam" }, 500);
103}
104});
111112if (isNaN(examId)) {
113return c.json<ApiResponse>({ success: false, error: "Invalid exam ID" }, 400);
114}
115116const exam = await db.getExamById(examId);
117if (!exam) {
118return c.json<ApiResponse>({ success: false, error: "Exam not found" }, 404);
119}
120122const course = await db.getCourseById(exam.course_id);
123if (!course) {
124return c.json<ApiResponse>({ success: false, error: "Course not found" }, 404);
125}
126128const enrolled = await db.isUserEnrolled(user.id, exam.course_id);
129if (!enrolled || !exam.is_published) {
130return c.json<ApiResponse>({ success: false, error: "Access denied" }, 403);
131}
132} else if (user.role === 'instructor' && course.instructor_id !== user.id) {
133return c.json<ApiResponse>({ success: false, error: "Access denied" }, 403);
134}
135155};
156157return c.json<ApiResponse<ExamAttempt>>({ success: true, data: examAttempt });
158} catch (error) {
159console.error("Get exam error:", error);
160return c.json<ApiResponse>({ success: false, error: "Failed to get exam" }, 500);
161}
162});
169170if (isNaN(examId)) {
171return c.json<ApiResponse>({ success: false, error: "Invalid exam ID" }, 400);
172}
173174const exam = await db.getExamById(examId);
175if (!exam) {
176return c.json<ApiResponse>({ success: false, error: "Exam not found" }, 404);
177}
178180const course = await db.getCourseById(exam.course_id);
181if (!course || course.instructor_id !== user.id) {
182return c.json<ApiResponse>({ success: false, error: "Access denied" }, 403);
183}
184185await db.publishExam(examId);
186return c.json<ApiResponse>({ success: true, data: { message: "Exam published successfully" } });
187} catch (error) {
188console.error("Publish exam error:", error);
189return c.json<ApiResponse>({ success: false, error: "Failed to publish exam" }, 500);
190}
191});
Reubencourses.ts22 matches
1import { Hono } from "https://esm.sh/hono@3.11.7";
2import type { CreateCourseRequest, ApiResponse, Course, User } from "../../shared/types.ts";
3import * as db from "../database/queries.ts";
4import { requireAuth, requireInstructor } from "./auth.ts";
26}
2728return c.json<ApiResponse<Course[]>>({ success: true, data: courseList });
29} catch (error) {
30console.error("Get courses error:", error);
31return c.json<ApiResponse>({ success: false, error: "Failed to get courses" }, 500);
32}
33});
4142if (!title || !description) {
43return c.json<ApiResponse>({ success: false, error: "Title and description are required" }, 400);
44}
4546const course = await db.createCourse(title, description, user.id);
47return c.json<ApiResponse<Course>>({ success: true, data: course });
48} catch (error) {
49console.error("Create course error:", error);
50return c.json<ApiResponse>({ success: false, error: "Failed to create course" }, 500);
51}
52});
5960if (isNaN(courseId)) {
61return c.json<ApiResponse>({ success: false, error: "Invalid course ID" }, 400);
62}
6364const course = await db.getCourseById(courseId);
65if (!course) {
66return c.json<ApiResponse>({ success: false, error: "Course not found" }, 404);
67}
6871const enrolled = await db.isUserEnrolled(user.id, courseId);
72if (!enrolled) {
73return c.json<ApiResponse>({ success: false, error: "Not enrolled in this course" }, 403);
74}
75course.enrolled = true;
76} else if (user.role === 'instructor' && course.instructor_id !== user.id) {
77return c.json<ApiResponse>({ success: false, error: "Access denied" }, 403);
78}
7980return c.json<ApiResponse<Course>>({ success: true, data: course });
81} catch (error) {
82console.error("Get course error:", error);
83return c.json<ApiResponse>({ success: false, error: "Failed to get course" }, 500);
84}
85});
9293if (isNaN(courseId)) {
94return c.json<ApiResponse>({ success: false, error: "Invalid course ID" }, 400);
95}
9697if (user.role !== 'student') {
98return c.json<ApiResponse>({ success: false, error: "Only students can enroll in courses" }, 403);
99}
100102const course = await db.getCourseById(courseId);
103if (!course) {
104return c.json<ApiResponse>({ success: false, error: "Course not found" }, 404);
105}
106108const alreadyEnrolled = await db.isUserEnrolled(user.id, courseId);
109if (alreadyEnrolled) {
110return c.json<ApiResponse>({ success: false, error: "Already enrolled in this course" }, 400);
111}
112113await db.enrollUser(user.id, courseId);
114return c.json<ApiResponse>({ success: true, data: { message: "Successfully enrolled" } });
115} catch (error) {
116console.error("Enroll error:", error);
117return c.json<ApiResponse>({ success: false, error: "Failed to enroll" }, 500);
118}
119});
126127if (isNaN(courseId)) {
128return c.json<ApiResponse>({ success: false, error: "Invalid course ID" }, 400);
129}
130132const course = await db.getCourseById(courseId);
133if (!course || course.instructor_id !== user.id) {
134return c.json<ApiResponse>({ success: false, error: "Access denied" }, 403);
135}
136137const students = await db.getCourseEnrollments(courseId);
138return c.json<ApiResponse<User[]>>({ success: true, data: students });
139} catch (error) {
140console.error("Get enrollments error:", error);
141return c.json<ApiResponse>({ success: false, error: "Failed to get enrollments" }, 500);
142}
143});
1import { Hono } from "https://esm.sh/hono@3.11.7";
2import { setCookie, getCookie, deleteCookie } from "https://esm.sh/hono@3.11.7/cookie";
3import type { LoginRequest, RegisterRequest, ApiResponse, User } from "../../shared/types.ts";
4import * as db from "../database/queries.ts";
532// Validate input
33if (!email || !password || !name || !role) {
34return c.json<ApiResponse>({ success: false, error: "All fields are required" }, 400);
35}
3637if (!['student', 'instructor'].includes(role)) {
38return c.json<ApiResponse>({ success: false, error: "Invalid role" }, 400);
39}
4042const existingUser = await db.getUserByEmail(email);
43if (existingUser) {
44return c.json<ApiResponse>({ success: false, error: "User already exists" }, 400);
45}
4664// Remove password hash from response
65const { password_hash, ...userResponse } = user as any;
66return c.json<ApiResponse<User>>({ success: true, data: userResponse });
67} catch (error) {
68console.error("Registration error:", error);
69return c.json<ApiResponse>({ success: false, error: "Registration failed" }, 500);
70}
71});
7879if (!email || !password) {
80return c.json<ApiResponse>({ success: false, error: "Email and password are required" }, 400);
81}
8284const user = await db.getUserByEmail(email);
85if (!user) {
86return c.json<ApiResponse>({ success: false, error: "Invalid credentials" }, 401);
87}
8889const passwordHash = await db.getUserPasswordHash(email);
90if (!passwordHash || !(await verifyPassword(password, passwordHash))) {
91return c.json<ApiResponse>({ success: false, error: "Invalid credentials" }, 401);
92}
93105});
106107return c.json<ApiResponse<User>>({ success: true, data: user });
108} catch (error) {
109console.error("Login error:", error);
110return c.json<ApiResponse>({ success: false, error: "Login failed" }, 500);
111}
112});
121
122deleteCookie(c, "session");
123return c.json<ApiResponse>({ success: true });
124} catch (error) {
125console.error("Logout error:", error);
126return c.json<ApiResponse>({ success: false, error: "Logout failed" }, 500);
127}
128});
133const sessionId = getCookie(c, "session");
134if (!sessionId) {
135return c.json<ApiResponse>({ success: false, error: "Not authenticated" }, 401);
136}
137138const user = await db.getSessionUser(sessionId);
139if (!user) {
140return c.json<ApiResponse>({ success: false, error: "Invalid session" }, 401);
141}
142143return c.json<ApiResponse<User>>({ success: true, data: user });
144} catch (error) {
145console.error("Get user error:", error);
146return c.json<ApiResponse>({ success: false, error: "Failed to get user" }, 500);
147}
148});
152const sessionId = getCookie(c, "session");
153if (!sessionId) {
154return c.json<ApiResponse>({ success: false, error: "Authentication required" }, 401);
155}
156157const user = await db.getSessionUser(sessionId);
158if (!user) {
159return c.json<ApiResponse>({ success: false, error: "Invalid session" }, 401);
160}
161168const user = c.get("user");
169if (!user || user.role !== 'instructor') {
170return c.json<ApiResponse>({ success: false, error: "Instructor access required" }, 403);
171}
172await next();
81}
8283// API Response types
84export interface ApiResponse<T = any> {
85success: boolean;
86data?: T;
37โ โ โโโ submissions.ts # Exam submissions
38โ โ โโโ static.ts # Static file serving
39โ โโโ index.ts # Main API server
40โโโ frontend/
41โ โโโ components/
61## Technology Stack
6263- **Backend**: Hono.js API framework
64- **Database**: SQLite with automatic migrations
65- **Frontend**: React with TypeScript
67- **Authentication**: Session-based auth with secure cookies
6869## API Endpoints
7071### Authentication
72- `POST /api/auth/register` - User registration
73- `POST /api/auth/login` - User login
74- `POST /api/auth/logout` - User logout
75- `GET /api/auth/me` - Get current user
7677### Courses
78- `GET /api/courses` - List all courses
79- `POST /api/courses` - Create new course (instructors only)
80- `GET /api/courses/:id` - Get course details
81- `POST /api/courses/:id/enroll` - Enroll in course
8283### Exams
84- `GET /api/courses/:id/exams` - List course exams
85- `POST /api/courses/:id/exams` - Create new exam
86- `GET /api/exams/:id` - Get exam details
87- `POST /api/exams/:id/submit` - Submit exam answers
8889### Submissions
90- `GET /api/exams/:id/submissions` - Get exam submissions (instructors)
91- `GET /api/submissions/:id` - Get specific submission details
19await runMigrations();
2021// API routes
22app.route('/api/auth', authRoutes);
23app.route('/api/advertisements', advertisementRoutes);
24app.route('/api/leads', leadRoutes);
25app.route('/api/followups', followupRoutes);
26app.route('/api/orders', orderRoutes);
27app.route('/api/debug', debugRoutes);
2829// Static file serving and main app
zerodha_pull_holdingsmain.tsx7 matches
5import { parse as parseQuery } from "npm:querystring";
67const apiKey = process.env.API_KEY;
8const apiSecret = process.env.API_SECRET;
9const username = process.env.USERNAME;
10const password = process.env.PASSWORD;
11const totpKey = process.env.TOTP_KEY;
12const loginUrl = `https://kite.zerodha.com/connect/login?v=3&api_key=${apiKey}`;
1314export default async function(interval: Interval) {
16console.log("requestToken", requestToken);
1718const kc = new KiteConnect({ api_key: apiKey });
1920async function generateSession() {
21try {
22const response = await kc.generateSession(requestToken, apiSecret);
23kc.setAccessToken(response.access_token);
24console.log("Session generated:", response);
5758// Step 2: Login request
59const loginRes = await fetch("https://kite.zerodha.com/api/login", {
60method: "POST",
61headers: { "Content-Type": "application/x-www-form-urlencoded" },
77});
7879await fetch("https://kite.zerodha.com/api/twofa", {
80method: "POST",
81headers: { "Content-Type": "application/x-www-form-urlencoded" },