From c09a5c758e89bb43f4750decdb6d9799cadbbbd3 Mon Sep 17 00:00:00 2001 From: Kobe Date: Fri, 30 May 2025 20:32:40 +0200 Subject: [PATCH] fix a bunch is settings --- __pycache__/forms.cpython-313.pyc | Bin 5301 -> 6574 bytes forms.py | 16 +++- routes/__pycache__/main.cpython-313.pyc | Bin 46556 -> 47563 bytes routes/__pycache__/trash.cpython-313.pyc | Bin 7171 -> 7391 bytes routes/main.py | 96 +++++++++++++--------- routes/trash.py | 55 +++++++------ static/js/rooms/fileManager.js | 2 +- static/js/settings.js | 61 ++++++++++++-- templates/settings/settings.html | 2 +- templates/settings/tabs/company_info.html | 88 ++++---------------- 10 files changed, 172 insertions(+), 148 deletions(-) diff --git a/__pycache__/forms.cpython-313.pyc b/__pycache__/forms.cpython-313.pyc index 4baab873e8609be8aa4fab610d91e4c9e7c73627..4f89d08fd62010afd035bd1314ef64549654727a 100644 GIT binary patch delta 1837 zcmaJ?O>7%Q6yA-0YkO_Sc5KHD%}=Ey8$yFpM@>vy5ljmaA#v=a38{tU*js1Q_(!vL zN`k~%LgK=y>?KG&M1=z!K#DActV)PgIiwPYHHbsz27*J+EfRtY^JZhm)GBlMJoDc7 z-pu#r?f4u1>x<4O9A{(55dNCk-0i;W46;Ao9r-pCWQLdo7h)35Bs*mQ0>hx*oQroK z{&wFG{L+XGTcsQ}Zk2=_Hk1kka^kJOYxj)*u-qsiW791WNoB;>J~w}5U|&??wo&uT zkYz@x+WO34n7*RixBbFiQr@%QW=ECZ?O`_$W-GvDfGf(VW86HYbJrc?j#)C5SOTx2 zaP1Sv1(rms+#kUxF)i>;^g2+l0bB=oL;21*)xQYS7y!`FB>=krGR&40k89pcjmt{b zRqq)CYXBe!a28;-Ht9yJ9D(^w0@#{Li3PEoN+B26#sOXehatVajl0AwwpJto71DVD z&4JyL7xEhdlCUMSSrjvZ#G4S*0~^yQCt>sLJM@>WAga+sTmxiO^^<0R*{huQ+>=2A z@99uVtjGue*NGeeYXFc4y#sKD05*t)GRncy0zgXx$@Tgy!7NUoSz}m(UJ4h%p>Zp|R>E;mj-!L4@1>uPqa05DUy_rOoE@C@1Gy;2)xl}s z%$@8e!rkqh36@HhJv6+#-9@X^9_~&0NVq52GsH|V3GWh{@J)5;6+KDgPxPQb&d&$1 zH(Jb>(uLiGP%evwoOHd2@{g|&@}A?wGq3>dNn8CKBa>T(UdNVIVM7wj!s8>dLUu5j zVw=T+fcmL>Hk(C)Bw=GzEbn4dqMR-Zd)D>2*g&+H6|f~*tdJhtMXSKJ&K0s1@(%2t zZaQDg711E%9tMDZUf_dBe)ii1C+%nsX3){tk2fT;oHLACM7FK86=jR@7B-$bZtY+ zqMv6ZZMxj>Rz959O9us8;6uu%-p?lK(@tM5T1#lM)B0lT<$N()*%q#%kBI~RPo%ga a`eu8dGFJ9|_NmXo?y&p(pA7ucxPJj&$KFu@ delta 630 zcmZXRPfrs;7{(cPsY|=N#Tvsl9B4eyt{{g(g91VR89hib4Qf1XHnJ>R+Ske^TRp zdB_GZ2~6=Bb0jhL*V{Bl%)7FTnZzs=JICfIle@oKXU?3I%C1fGur2_Lz&-xiE)6cB zECaAn2~hV}P*r##{V<`#3jbzhIZq#4FQC&8IKTk#xbvWo*u-tr&m@H5c~K*3c^;*q z-2{fw(EM6WbVsYgXvYCH{CYt5`H!p4Fme&PPhl()8?V%xwMh-tBU>_=%V>N)o_W24 z?{zc(O(j)Al7xRpCh!En8T1tBl@MCgXil!x$}-< diff --git a/forms.py b/forms.py index 715229c..5e05847 100644 --- a/forms.py +++ b/forms.py @@ -56,4 +56,18 @@ class ConversationForm(FlaskForm): def __init__(self, *args, **kwargs): super(ConversationForm, self).__init__(*args, **kwargs) - self.members.choices = [(u.id, f"{u.username} {u.last_name}") for u in User.query.filter_by(is_active=True).all()] \ No newline at end of file + self.members.choices = [(u.id, f"{u.username} {u.last_name}") for u in User.query.filter_by(is_active=True).all()] + +class CompanySettingsForm(FlaskForm): + company_name = StringField('Company Name', validators=[Optional(), Length(max=100)]) + company_website = StringField('Website', validators=[Optional(), Length(max=200)]) + company_email = StringField('Email', validators=[Optional(), Email(), Length(max=100)]) + company_phone = StringField('Phone', validators=[Optional(), Length(max=20)]) + company_address = StringField('Address', validators=[Optional(), Length(max=200)]) + company_city = StringField('City', validators=[Optional(), Length(max=100)]) + company_state = StringField('State', validators=[Optional(), Length(max=100)]) + company_zip = StringField('ZIP Code', validators=[Optional(), Length(max=20)]) + company_country = StringField('Country', validators=[Optional(), Length(max=100)]) + company_description = TextAreaField('Description', validators=[Optional()]) + company_industry = StringField('Industry', validators=[Optional(), Length(max=100)]) + company_logo = FileField('Company Logo', validators=[FileAllowed(['jpg', 'jpeg', 'png', 'gif'], 'Images only!')]) \ No newline at end of file diff --git a/routes/__pycache__/main.cpython-313.pyc b/routes/__pycache__/main.cpython-313.pyc index 55ec96ed34a42e478f849189047b237d3340cb90..88f675823406e12795576de9cc1e3c5c1f3c608b 100644 GIT binary patch delta 6500 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 Tdz>9!c)LlzR^*G6H|zfgHW+dE delta 5752 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 QBRu}bdgBvjwpii)f4`#1UjP6A diff --git a/routes/__pycache__/trash.cpython-313.pyc b/routes/__pycache__/trash.cpython-313.pyc index 1522d8f7f01359792e7b527aa64a6797cfdde03e..af2d83212033100c586cd7d5875725e064610f4f 100644 GIT binary patch delta 2245 zcma)7U2Gdg5Z*oe?6u>+CjN~R=kn8%BQ&IS(l$-nCgjIyk~YO|Bv7IT<6IhpW2bvA zQu{#o5l|!qL??-vRA$%9*10X1V9OZ+CbPz{z zNO=w)!o0GCYs+-^s4US$K1u1~FZeeeyObZS^|(>7kp~_QLCi1%-8v~{q`X9ROLBHr z%1+V*W@Pq%>5%s?bGsJuv8aD#G*q;cnBt?jgV&d)4A zzJZHoaD|w*N1=dJ1h^l-1z-Vi00aTb01U1M83DGp z3EP-hjH`6HnmypIlRQnz(-Y}Q+NM1161*LtbWlmo=cqI>mCi_XNcqV1JKnSSpsWM9>o=C;01)T zTm+2~_K>mScI6#&g`!qeDBpV`kp#yx^;pGiD;h;@>~+B!<>FozslsO}?z5(U1v&5a z223UY#-bZavNDem1@l!^b!haCSwIIEmjf>$RE7jJ7EyBCc9O6ptnFNpu`A1u@{I8= zU_2%;`?fF_hg)~gN)VRhW=5^bdSJH^ZXXYqGSu>WFD(7X%Z$VPHDIC?_ynjS1HZPU;a=BpEY-zWB9;%gc624 zg{ROSQw^HJ_nh*Gamu|+9|Wdz8)w_^KB2_eg`!+ZX4T!utL(qL6OQIP-U(+bCv!Eo zxi$QYqv$%>&^NPVHh)6MPfLQ)Jp$`~At}hSQYt-_P6;%Zn`x#2RtViWdT4m0yLY00 zWVp94t~?p2pF4P1!69`tY=oYq;lD*^ika;=P9jG zehO@vGp2?U9yey4(WV<+d#7P_LUWnS_DatKdwVkqk^V9ZR|$ z%271S7G{RdF7W&t4u%j-F)RG!Pg!EmpjA@McjKGE`a)3Df?^>U)q>H>F*O)f zgS~~|fEFBB3J#ufu33<;?o{t8XK{vBsv>7%Z^zCIzdd{*To5}nvE%ZHCJuj*Qsa+) zo>9jiD~wCpxU^I?^}21P!gqS-{La&R=apAO;W;Y{v+hOy$mt{VM+&~Jns4jE(JOh? zw^j8G7kq~_-=QU6{FMD0Z{$?(iX&Wb)M}2}f}=@uG%fUAid~GUjwaR7S#b1dj-Ia_ zeZQKJuV$Sfo3}th8VMChy+-QK#Z*$SlGXz0&`8HJ*|S1Cuen}!%@v5C5#e0ma)U|) zmFz2!evR}mlYyJW{+j(|dojo|3Ey=4-?E);RRfJnZc!!T@9QNp-KWk@tF8x^Nz01cf41%8=)$qZ9a>=blDp$_LUnh2MY?XSS|P}vGEDC0 zT4J?mv3p;C1NX`Ho^5P%t-&6P@Yk9fVj=!|xs_?Ihj^yB9x;JjYu|4&U2p1k4(v6# zKHG)a?z6o-L$OjhT6wUV!j;tdCO3IJBkiRbrh{27f6HLigfYH>T9;5O!yBmQE7YUx41Zi%gS+vX32`2PF8r$* I6h^$i0X2bko>5r9MBg7z-}9dL zKIc8>{pgL(*ETp8oX$$b<T^@KSWEpL>fv^C zzuYHNIf(Y*CKR{qt6FCQ285`0pLZy9+NTtM3`joEi@%4ZWuUNH9G0quHiW~thP{Dz zVZwC0{DRFiFJULUYiY)UGz>X8En(yF>Agtjz%8{b*vWeL~n9&k6T1)5aH zMlvZHfu%z%)2Wfs%y`-`(NR_6<{$`tN;uH8TFBG1aG-tcit7&Ux^UTTU~xOTg*(x1 z4tqk5{}V2c3DIo;+W~d}i034W*XacVghrzrRM>hDO!c8OPeLx8D~wN!Fn^V!GRF6Z z!0{cXx%RVntJdN!c8M2CjIiDIt?ZKNb#~KdB{|cuhq*ir>=m!qn&2fDmpVG&G{KXZ`IA+2;^IwsFFStpDevvr zSCzSkR*PqxGS_VmqTz7a9Jj|w2QJ6hf|jGheHI9+;71C;K>y zr|Q(Psbi;3Or1D0_*MA)u`j!3+#60tuX!3~J#BB1d6UKFyXN+unwXk6vt!2HG*{nv zuJ`Pw-g5(I2hP`At=4uYw7sMH&V!|$2d5)?c>Ay6?OOJ*o;_O19@Snx@fSi9xZ8AV z@n->{hHWPHw!gJsLZ0SZ5|SUky$neno%l+`r;|X51kPJD63|G8PS%&m`dQLBM;vd) zUXAIbzC`Lj-aDPrNWDfj>ZH3wx@Sob`^X)P-?{BY9{&O|*?e;jSyR?bw|p1+CNy1l zvHJ)0@|y3DUL4b^dS@Nc>kj4bd5OE-RbhVoOuFlP+e}y5Dx)pZl}Jl8ApH`MxE}Je zuDV!_Ass1X#?{5??t(<`25_^_>jM4oze4)}VAMgH&=-hyfiC8=wJV!X9T`t=rU$tV tMwI#+hxrPO@eLH2K@pBO(ApWamdW+s*3{ya3l+%Z0oa0X5xy2|{{TL+u3Z2C diff --git a/routes/main.py b/routes/main.py index f82d73a..c874956 100644 --- a/routes/main.py +++ b/routes/main.py @@ -9,6 +9,7 @@ from datetime import datetime, timedelta import logging import sys import time +from forms import CompanySettingsForm # Set up logging to show in console logging.basicConfig( @@ -407,54 +408,61 @@ def init_routes(main_bp): flash('Only administrators can access settings.', 'error') return redirect(url_for('main.dashboard')) - site_settings = SiteSettings.get_settings() + # Get active tab from URL or default to colors active_tab = request.args.get('tab', 'colors') + # Get site settings + site_settings = SiteSettings.get_settings() + # Get events data if events tab is active events = None - total_pages = 1 + total_pages = 0 current_page = 1 users = [] if active_tab == 'events': # Get filter parameters - event_type = request.args.get('event_type') + event_type = request.args.get('event_type', '') date_range = request.args.get('date_range', '7d') - user_id = request.args.get('user_id') + user_id = request.args.get('user_id', '') page = request.args.get('page', 1, type=int) - per_page = 50 - - # Calculate date range - end_date = datetime.utcnow() - if date_range == '24h': - start_date = end_date - timedelta(days=1) - elif date_range == '7d': - start_date = end_date - timedelta(days=7) - elif date_range == '30d': - start_date = end_date - timedelta(days=30) - else: - start_date = None + per_page = 10 # Build query query = Event.query + # Apply filters if event_type: - query = query.filter_by(event_type=event_type) - if start_date: - query = query.filter(Event.timestamp >= start_date) + query = query.filter(Event.event_type == event_type) if user_id: - query = query.filter_by(user_id=user_id) - - # Get total count for pagination - total_events = query.count() - total_pages = (total_events + per_page - 1) // per_page + query = query.filter(Event.user_id == user_id) + if date_range: + cutoff_date = datetime.utcnow() - timedelta(days=int(date_range[:-1])) + query = query.filter(Event.timestamp >= cutoff_date) # Get paginated events events = query.order_by(Event.timestamp.desc()).paginate(page=page, per_page=per_page) + total_pages = events.pages + current_page = events.page # Get all users for filter dropdown users = User.query.order_by(User.username).all() + # Create form for company settings + company_form = CompanySettingsForm() + if request.method == 'GET': + company_form.company_name.data = site_settings.company_name + company_form.company_website.data = site_settings.company_website + company_form.company_email.data = site_settings.company_email + company_form.company_phone.data = site_settings.company_phone + company_form.company_address.data = site_settings.company_address + company_form.company_city.data = site_settings.company_city + company_form.company_state.data = site_settings.company_state + company_form.company_zip.data = site_settings.company_zip + company_form.company_country.data = site_settings.company_country + company_form.company_description.data = site_settings.company_description + company_form.company_industry.data = site_settings.company_industry + return render_template('settings/settings.html', primary_color=site_settings.primary_color, secondary_color=site_settings.secondary_color, @@ -464,7 +472,7 @@ def init_routes(main_bp): total_pages=total_pages, current_page=current_page, users=users, - csrf_token=session.get('csrf_token')) + form=company_form) @main_bp.route('/settings/colors', methods=['POST']) @login_required @@ -544,12 +552,17 @@ def init_routes(main_bp): flash('Only administrators can update settings.', 'error') return redirect(url_for('main.dashboard')) + form = CompanySettingsForm() + if not form.validate(): + flash('Please check the form for errors.', 'error') + return redirect(url_for('main.settings')) + site_settings = SiteSettings.get_settings() # Handle logo upload - if 'company_logo' in request.files: - logo_file = request.files['company_logo'] - if logo_file and logo_file.filename: + if form.company_logo.data: + logo_file = form.company_logo.data + if logo_file.filename: # Delete old logo if it exists if site_settings.company_logo: old_logo_path = os.path.join('static', 'uploads', 'company_logos', site_settings.company_logo) @@ -565,17 +578,17 @@ def init_routes(main_bp): site_settings.company_logo = filename # Update all company fields - site_settings.company_name = request.form.get('company_name') - site_settings.company_website = request.form.get('company_website') - site_settings.company_email = request.form.get('company_email') - site_settings.company_phone = request.form.get('company_phone') - site_settings.company_address = request.form.get('company_address') - site_settings.company_city = request.form.get('company_city') - site_settings.company_state = request.form.get('company_state') - site_settings.company_zip = request.form.get('company_zip') - site_settings.company_country = request.form.get('company_country') - site_settings.company_description = request.form.get('company_description') - site_settings.company_industry = request.form.get('company_industry') + site_settings.company_name = form.company_name.data + site_settings.company_website = form.company_website.data + site_settings.company_email = form.company_email.data + site_settings.company_phone = form.company_phone.data + site_settings.company_address = form.company_address.data + site_settings.company_city = form.company_city.data + site_settings.company_state = form.company_state.data + site_settings.company_zip = form.company_zip.data + site_settings.company_country = form.company_country.data + site_settings.company_description = form.company_description.data + site_settings.company_industry = form.company_industry.data try: db.session.commit() @@ -599,7 +612,7 @@ def init_routes(main_bp): 'company_country': site_settings.company_country, 'company_description': site_settings.company_description, 'company_industry': site_settings.company_industry, - 'logo_updated': bool(request.files.get('company_logo')) + 'logo_updated': bool(form.company_logo.data) } } ) @@ -607,10 +620,11 @@ def init_routes(main_bp): flash('Company settings updated successfully!', 'success') except Exception as e: + logger.error(f"Error updating company settings: {str(e)}") db.session.rollback() flash('An error occurred while updating company settings.', 'error') - return redirect(url_for('main.settings', tab='general')) + return redirect(url_for('main.settings')) @main_bp.route('/dynamic-colors.css') def dynamic_colors(): diff --git a/routes/trash.py b/routes/trash.py index ee8726e..3148252 100644 --- a/routes/trash.py +++ b/routes/trash.py @@ -1,6 +1,6 @@ from flask import Blueprint, jsonify, request, abort from flask_login import login_required, current_user -from models import db, Room, RoomFile, TrashedFile +from models import db, Room, RoomFile, TrashedFile, UserStarredFile from utils import user_has_permission, clean_path import os from datetime import datetime @@ -99,29 +99,34 @@ def permanently_delete_file(room_id, trash_id): @trash_bp.route('//trash/empty', methods=['POST']) @login_required def empty_trash(room_id): - room = Room.query.get_or_404(room_id) - if not user_has_permission(room, 'can_delete'): - abort(403) - - # Get all trashed files for this room - trashed_files = TrashedFile.query.filter_by(room_id=room_id).all() - room_files = RoomFile.query.filter_by(room_id=room_id, deleted=True).all() - - # Delete physical files - room_dir = os.path.join('/data/rooms', str(room_id)) - for file in trashed_files + room_files: - try: - if file.type == 'file': - file_path = os.path.join(room_dir, file.original_path if hasattr(file, 'original_path') else file.path, file.name) + """Empty the trash for a specific room.""" + try: + # Get all trashed files + trashed_files = TrashedFile.query.filter_by(room_id=room_id).all() + + # Delete physical files first + for file in trashed_files: + try: + file_path = os.path.join(current_app.config['UPLOAD_FOLDER'], str(room_id), file.name) if os.path.exists(file_path): os.remove(file_path) - except Exception as e: - print(f"Error deleting physical file {file.name}: {str(e)}") - continue - - # Delete all trashed files from both tables - TrashedFile.query.filter_by(room_id=room_id).delete() - RoomFile.query.filter_by(room_id=room_id, deleted=True).delete() - db.session.commit() - - return jsonify({'success': True}) \ No newline at end of file + except Exception as e: + print(f"Error deleting physical file {file.name}: {str(e)}") + continue + + # Delete all starred file references for the trashed files + room_files = RoomFile.query.filter_by(room_id=room_id, deleted=True).all() + for file in room_files: + UserStarredFile.query.filter_by(file_id=file.id).delete() + + # Delete all trashed files from both tables + TrashedFile.query.filter_by(room_id=room_id).delete() + RoomFile.query.filter_by(room_id=room_id, deleted=True).delete() + + db.session.commit() + + return jsonify({'success': True}) + except Exception as e: + db.session.rollback() + print(f"Error emptying trash: {str(e)}") + return jsonify({'success': False, 'error': str(e)}), 500 \ No newline at end of file diff --git a/static/js/rooms/fileManager.js b/static/js/rooms/fileManager.js index 039c3ac..823a39d 100644 --- a/static/js/rooms/fileManager.js +++ b/static/js/rooms/fileManager.js @@ -392,7 +392,7 @@ export class FileManager { */ async downloadFile(filename, path = '') { console.log('[FileManager] Downloading file:', { filename, path }); - const url = `/api/rooms/${this.roomManager.roomId}/files/${encodeURIComponent(filename)}`; + let url = `/api/rooms/${this.roomManager.roomId}/files/${encodeURIComponent(filename)}`; if (path) { url += `?path=${encodeURIComponent(path)}`; } diff --git a/static/js/settings.js b/static/js/settings.js index 9a6b970..07ac64e 100644 --- a/static/js/settings.js +++ b/static/js/settings.js @@ -12,6 +12,7 @@ document.addEventListener('DOMContentLoaded', function() { const primaryColorInput = document.getElementById('primaryColor'); const secondaryColorInput = document.getElementById('secondaryColor'); const colorSettingsForm = document.getElementById('colorSettingsForm'); + const companyInfoForm = document.getElementById('companyInfoForm'); // Get all tab buttons const settingsTabs = document.querySelectorAll('[data-bs-toggle="tab"]'); @@ -73,10 +74,14 @@ document.addEventListener('DOMContentLoaded', function() { eventsTableBody.innerHTML = 'Loading events...'; } + // Get CSRF token + const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content'); + // Fetch events data fetch(`/settings/events?event_type=${eventType}&date_range=${dateRange}&user_id=${userId}&page=${page}`, { headers: { - 'X-Requested-With': 'XMLHttpRequest' + 'X-Requested-With': 'XMLHttpRequest', + 'X-CSRF-Token': csrfToken } }) .then(response => response.text()) @@ -303,11 +308,55 @@ document.addEventListener('DOMContentLoaded', function() { // Handle form submission if (colorSettingsForm) { colorSettingsForm.addEventListener('submit', function(e) { - console.log('[Settings] Form submitted with values:', { - primary: primaryColorInput.value, - secondary: secondaryColorInput.value, - csrf: document.querySelector('meta[name="csrf-token"]').getAttribute('content'), - timestamp: new Date().toISOString() + e.preventDefault(); // Prevent default form submission + + const formData = new FormData(colorSettingsForm); + const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content'); + + fetch(colorSettingsForm.action, { + method: 'POST', + headers: { + 'X-CSRF-Token': csrfToken + }, + body: formData + }) + .then(response => { + if (response.ok) { + window.location.reload(); // Reload to show updated colors + } else { + throw new Error('Failed to update colors'); + } + }) + .catch(error => { + console.error('Error updating colors:', error); + alert('Failed to update colors. Please try again.'); + }); + }); + } + + // Handle company info form submission + if (companyInfoForm) { + companyInfoForm.addEventListener('submit', function(e) { + e.preventDefault(); + + const formData = new FormData(companyInfoForm); + const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content'); + formData.append('csrf_token', csrfToken); + + fetch(companyInfoForm.action, { + method: 'POST', + body: formData + }) + .then(response => { + if (response.ok) { + window.location.reload(); // Reload to show updated info + } else { + throw new Error('Failed to update company info'); + } + }) + .catch(error => { + console.error('Error updating company info:', error); + alert('Failed to update company info. Please try again.'); }); }); } diff --git a/templates/settings/settings.html b/templates/settings/settings.html index 55034ef..9662c52 100644 --- a/templates/settings/settings.html +++ b/templates/settings/settings.html @@ -63,7 +63,7 @@
- {{ company_info_tab(site_settings, csrf_token) }} + {{ company_info_tab(site_settings, form) }}
diff --git a/templates/settings/tabs/company_info.html b/templates/settings/tabs/company_info.html index 448211f..c468131 100644 --- a/templates/settings/tabs/company_info.html +++ b/templates/settings/tabs/company_info.html @@ -1,11 +1,11 @@ -{% macro company_info_tab(site_settings, csrf_token) %} +{% macro company_info_tab(site_settings, form) %}
-
- + + {{ form.csrf_token }}
@@ -20,50 +20,26 @@ class="img-thumbnail" style="max-height: 100px; max-width: 200px;"> {% endif %} - + {{ form.company_logo(class="form-control", accept="image/*") }}
Upload your company logo. Recommended size: 200x100 pixels.
- + {{ form.company_name(class="form-control", placeholder="Enter your company name") }}
This name will be displayed in the website title and navigation bar.
- + {{ form.company_website(class="form-control", placeholder="https://example.com") }}
- + {{ form.company_email(class="form-control", placeholder="contact@company.com") }}
- + {{ form.company_phone(class="form-control", placeholder="+1 (555) 123-4567") }}
@@ -72,50 +48,25 @@
Address Information
- + {{ form.company_address(class="form-control", placeholder="123 Business Street") }}
- + {{ form.company_city(class="form-control", placeholder="City") }}
- + {{ form.company_state(class="form-control", placeholder="State") }}
- + {{ form.company_zip(class="form-control", placeholder="ZIP") }}
- + {{ form.company_country(class="form-control", placeholder="Country") }}
@@ -124,20 +75,11 @@
Additional Information
- + {{ form.company_description(class="form-control", rows="3", placeholder="Brief description of your company") }}
- + {{ form.company_industry(class="form-control", placeholder="e.g., Technology, Healthcare, Finance") }}