diff --git a/app.py b/app.py index 99f8cc0..4d87312 100644 --- a/app.py +++ b/app.py @@ -142,6 +142,20 @@ def profile(): team=current_user.team, manager=current_user.manager) +@app.route('/set_theme', methods=['POST']) +def set_theme(): + theme = request.json.get('theme', 'modern') # Default to 'modern' + if theme not in ['modern', 'dark', 'light']: + return {"error": "Invalid theme"}, 400 + + if current_user.is_authenticated: + current_user.theme = theme + db.session.commit() + session['theme'] = theme # Update session theme for guests + return {"message": "Theme updated successfully"}, 200 + + + @@ -184,8 +198,8 @@ notebook = { @app.context_processor def inject_theme(): - # Default to 'dark' if the theme is not set in the session or user - theme = session.get('theme', current_user.theme if current_user.is_authenticated else 'dark') + # Default to 'modern' if no theme is set in the session or user + theme = session.get('theme', current_user.theme if current_user.is_authenticated else 'modern') return dict(theme=theme) @app.context_processor @@ -528,9 +542,36 @@ def login(): def notebook_page(): if request.method == 'POST': category = request.form.get('category') - entry = request.form.get('entry') - if category in notebook and entry: - notebook[category].append(entry) + entry = request.form.get('entry', '').strip() # Strip whitespace from the entry + + if not category or not entry: + flash("Category and entry cannot be empty.", "error") + return redirect(url_for('notebook_page')) + + if category not in notebook: + flash("Invalid category selected.", "error") + return redirect(url_for('notebook_page')) + + # Input validation + if category == "ips": + # Ensure valid IP address + ip_pattern = re.compile( + r'^((25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)$' + ) + if not ip_pattern.match(entry): + flash("Invalid IP address format.", "error") + return redirect(url_for('notebook_page')) + elif category == "notes": + # Ensure notes are over 1 character + if len(entry) < 2: + flash("Notes must be at least 2 characters long.", "error") + return redirect(url_for('notebook_page')) + + # Add valid entry to the notebook + notebook[category].append(entry) + flash(f"Entry added to {category.capitalize()}!", "success") + return redirect(url_for('notebook_page')) + return render_template('notebook.html', notebook=notebook) @@ -539,7 +580,10 @@ def notebook_page(): @login_required def delete_entry(category, index): if category in notebook and 0 <= index < len(notebook[category]): - notebook[category].pop(index) + deleted_entry = notebook[category].pop(index) + flash(f"Deleted entry: {deleted_entry} from {category.capitalize()}.", "info") + else: + flash("Invalid entry or category.", "error") return redirect(url_for('notebook_page')) # Logout Route @@ -549,6 +593,103 @@ def logout(): logout_user() flash('You have been logged out.') return redirect(url_for('login')) + + + + + + + + + + + + + + + + + + +def aggregate_content(): + """ + Aggregates content from all module files under the Modules directory. + Returns a list of dictionaries with 'title' and 'content'. + """ + content_list = [] + modules_dir = "Modules" + + for root, _, files in os.walk(modules_dir): + for file in files: + if file.endswith(".py") and not file.startswith("__"): + module_path = os.path.join(root, file).replace("/", ".").replace("\\", ".")[:-3] + try: + module = importlib.import_module(module_path) + if hasattr(module, "get_content"): + content_list.extend(module.get_content()) + except Exception as e: + print(f"Error importing {module_path}: {e}") + + return content_list + + + +def perform_search(query): + """ + Searches the aggregated content for matching titles or content. + """ + all_content = aggregate_content() + query = query.lower() + results = [ + { + "title": item["title"], + "snippet": item["content"][:150] + "...", # Return the first 150 characters as a snippet + "module": item.get("module", "Unknown") # Optional: Include module info + } + for item in all_content + if query in item["title"].lower() or query in item["content"].lower() + ] + return results + +@app.route('/search', methods=['GET']) +def search(): + query = request.args.get('query', '').strip() + if not query: + flash("Search query cannot be empty.", "error") + return redirect(url_for('home')) + + # Perform search + results = perform_search(query) + + # Render results + return render_template('search_results.html', query=query, results=results) + + + + + + + + + + + + + + + + + + + + + + + + + + + if __name__ == '__main__':