File size: 7,945 Bytes
da90401
 
 
 
b3574fc
da90401
c001f24
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
da90401
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e311892
da90401
 
 
 
 
 
 
e311892
 
 
 
 
 
b3574fc
e311892
 
 
 
 
b3574fc
e311892
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b3574fc
 
 
 
 
 
 
 
 
 
 
 
 
 
e311892
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
da90401
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
from flask import Blueprint, send_from_directory, current_app, request, jsonify
from flask_login import login_required, current_user
from utils import get_db_connection
import os
import base64
from datetime import datetime

image_bp = Blueprint('image_bp', __name__)

@image_bp.route('/processed/<path:filename>')
def serve_processed_image(filename):
    current_app.logger.info(f"Serving processed image: {filename}")
    return send_from_directory(current_app.config['PROCESSED_FOLDER'], filename)

@image_bp.route('/tmp/<path:filename>')
def serve_tmp_image(filename):
    current_app.logger.info(f"Serving temporary image: {filename}")
    return send_from_directory(current_app.config['TEMP_FOLDER'], filename)

# Proxy routes for /neetprep/processed and /neetprep/tmp
@image_bp.route('/neetprep/processed/<path:filename>')
def serve_neetprep_processed_image(filename):
    current_app.logger.info(f"Serving /neetprep/processed image: {filename}")
    return send_from_directory(current_app.config['PROCESSED_FOLDER'], filename)

@image_bp.route('/neetprep/tmp/<path:filename>')
def serve_neetprep_tmp_image(filename):
    current_app.logger.info(f"Serving /neetprep/tmp image: {filename}")
    return send_from_directory(current_app.config['TEMP_FOLDER'], filename)

@image_bp.route('/save_note_image', methods=['POST'])
@login_required
def save_note_image():
    try:
        if 'image' not in request.files:
            return jsonify({'error': 'No image file provided'}), 400
            
        file = request.files['image']
        image_id = request.form.get('image_id')
        session_id = request.form.get('session_id')
        
        if not image_id or not session_id:
             return jsonify({'error': 'Missing image_id or session_id'}), 400

        # Validate ownership
        conn = get_db_connection()
        img = conn.execute("SELECT i.id, s.user_id FROM images i JOIN sessions s ON i.session_id = s.id WHERE i.id = ?", (image_id,)).fetchone()
        
        if not img or img['user_id'] != current_user.id:
            conn.close()
            return jsonify({'error': 'Unauthorized or image not found'}), 403

        # Save the file
        filename = f"note_{session_id}_{image_id}_{int(datetime.now().timestamp())}.png"
        save_path = os.path.join(current_app.config['PROCESSED_FOLDER'], filename)
        file.save(save_path)
        
        # Update DB
        conn.execute("UPDATE images SET note_filename = ? WHERE id = ?", (filename, image_id))
        conn.commit()
        conn.close()
        
        return jsonify({'success': True, 'filename': filename})

    except Exception as e:
        current_app.logger.error(f"Error saving note: {e}")
        return jsonify({'error': str(e)}), 500

@image_bp.route('/toggle_note_in_pdf', methods=['POST'])
@login_required
def toggle_note_in_pdf():
    """Toggle whether a note should be included in the generated PDF."""
    try:
        data = request.json
        image_id = data.get('image_id')
        include = data.get('include', True)

        if not image_id:
            return jsonify({'error': 'Missing image_id'}), 400

        conn = get_db_connection()
        img = conn.execute("""
            SELECT i.id, s.user_id FROM images i
            JOIN sessions s ON i.session_id = s.id WHERE i.id = ?
        """, (image_id,)).fetchone()

        if not img or img['user_id'] != current_user.id:
            conn.close()
            return jsonify({'error': 'Unauthorized'}), 403

        conn.execute("UPDATE images SET include_note_in_pdf = ? WHERE id = ?",
                     (1 if include else 0, image_id))
        conn.commit()
        conn.close()

        return jsonify({'success': True, 'include': include})

    except Exception as e:
        current_app.logger.error(f"Error toggling note in PDF: {e}")
        return jsonify({'error': str(e)}), 500

@image_bp.route('/delete_note', methods=['POST'])
@login_required
def delete_note():
    """Delete a note image for a question."""
    try:
        data = request.json
        image_id = data.get('image_id')

        if not image_id:
            return jsonify({'error': 'Missing image_id'}), 400

        conn = get_db_connection()
        img = conn.execute("""
            SELECT i.id, i.note_filename, s.user_id FROM images i
            JOIN sessions s ON i.session_id = s.id WHERE i.id = ?
        """, (image_id,)).fetchone()

        if not img or img['user_id'] != current_user.id:
            conn.close()
            return jsonify({'error': 'Unauthorized'}), 403

        # Delete the file if it exists
        if img['note_filename']:
            note_path = os.path.join(current_app.config['PROCESSED_FOLDER'], img['note_filename'])
            if os.path.exists(note_path):
                os.remove(note_path)

        conn.execute("UPDATE images SET note_filename = NULL, note_json = NULL WHERE id = ?", (image_id,))
        conn.commit()
        conn.close()

        return jsonify({'success': True})

    except Exception as e:
        current_app.logger.error(f"Error deleting note: {e}")
        return jsonify({'error': str(e)}), 500


@image_bp.route('/save_note_json', methods=['POST'])
@login_required
def save_note_json():
    """Save revision notes as JSON and rasterized PNG for PDF/quiz display."""
    try:
        data = request.json
        image_id = data.get('image_id')
        session_id = data.get('session_id')
        json_data = data.get('json_data')
        image_data = data.get('image_data')

        if not image_id or not session_id or not json_data:
            return jsonify({'error': 'Missing required fields'}), 400

        # Validate ownership
        conn = get_db_connection()
        img = conn.execute("""
            SELECT i.id, s.user_id FROM images i
            JOIN sessions s ON i.session_id = s.id WHERE i.id = ?
        """, (image_id,)).fetchone()

        if not img or img['user_id'] != current_user.id:
            conn.close()
            return jsonify({'error': 'Unauthorized'}), 403

        # Save JSON to database
        conn.execute("UPDATE images SET note_json = ? WHERE id = ?", (json_data, image_id))

        # Save rasterized PNG if provided (needed for PDF generation and quiz display)
        if image_data and image_data.startswith('data:image/'):
            # Strip the data URL prefix (e.g. "data:image/png;base64,")
            header, encoded = image_data.split(',', 1)
            img_bytes = base64.b64decode(encoded)

            filename = f"note_{session_id}_{image_id}_{int(datetime.now().timestamp())}.png"
            save_path = os.path.join(current_app.config['PROCESSED_FOLDER'], filename)
            with open(save_path, 'wb') as f:
                f.write(img_bytes)

            conn.execute("UPDATE images SET note_filename = ? WHERE id = ?", (filename, image_id))

        conn.commit()
        conn.close()

        return jsonify({'success': True})

    except Exception as e:
        current_app.logger.error(f"Error saving note JSON: {e}")
        return jsonify({'error': str(e)}), 500


@image_bp.route('/get_note_json/<int:image_id>')
@login_required
def get_note_json(image_id):
    """Get revision notes as JSON."""
    try:
        conn = get_db_connection()
        img = conn.execute("""
            SELECT i.note_json, s.user_id FROM images i
            JOIN sessions s ON i.session_id = s.id WHERE i.id = ?
        """, (image_id,)).fetchone()

        if not img or img['user_id'] != current_user.id:
            conn.close()
            return jsonify({'error': 'Unauthorized'}), 403

        conn.close()

        if img['note_json']:
            return jsonify({'success': True, 'json_data': img['note_json']})
        else:
            return jsonify({'success': False, 'error': 'No note found'}), 404

    except Exception as e:
        current_app.logger.error(f"Error getting note JSON: {e}")
        return jsonify({'error': str(e)}), 500