import os, sqlite3, secrets, smtplib, imaplib, email, socket, json, time, re import requests from dotenv import load_dotenv from bs4 import BeautifulSoup from email.utils import parsedate_to_datetime from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart from email.header import decode_header from functools import wraps from flask import Flask, render_template, request, redirect, url_for, session, flash, g, jsonify from werkzeug.security import generate_password_hash, check_password_hash from google import genai from apify_client import ApifyClient from werkzeug.utils import secure_filename load_dotenv(os.path.join(os.path.dirname(__file__), '.env')) app = Flask(__name__) app.secret_key = os.environ.get('FLASK_SECRET_KEY', secrets.token_hex(32)) DB = os.path.join(os.path.dirname(__file__), 'tekstil.db') UPLOAD_FOLDER = os.path.join(os.path.dirname(__file__), 'static', 'uploads') app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER ALLOWED_EXT = {'png', 'jpg', 'jpeg', 'gif', 'webp'} # Apify Ayarlari APIFY_TOKEN = os.environ.get('APIFY_TOKEN', '') APIFY_CLIENT = ApifyClient(APIFY_TOKEN) # Google Gemini Ayarlari GEMINI_API_KEY = os.environ.get('GEMINI_API_KEY', '') GEMINI_CLIENT = genai.Client(api_key=GEMINI_API_KEY) def allowed_file(filename): return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXT def get_db(): if 'db' not in g: g.db = sqlite3.connect(DB) g.db.row_factory = sqlite3.Row return g.db @app.teardown_appcontext def close_db(e): db = g.pop('db', None) if db: db.close() def login_required(f): @wraps(f) def decorated(*args, **kwargs): if 'uid' not in session and 'firma_id' not in session: return redirect(url_for('login')) return f(*args, **kwargs) return decorated @app.route('/', methods=['GET', 'POST']) def login(): if request.method == 'POST': db = get_db() giris = request.form.get('kullanici_adi','').strip() sifre = request.form.get('sifre','') # Firma girişi (e-posta ile) if '@' in giris: firma = db.execute("SELECT * FROM firmalar WHERE email=? AND aktif=1", (giris.lower(),)).fetchone() if firma and check_password_hash(firma['sifre'], sifre): if not firma['onay']: flash('Hesabınız henüz onaylanmamış. Lütfen bekleyin.', 'warning') return redirect(url_for('login')) session['firma_id'] = firma['id'] session['firma_adi'] = firma['firma_adi'] session['yetkili'] = firma['yetkili_adi'] session['firma_logo'] = firma['logo'] session['giris_turu'] = 'firma' return redirect('/firma-admin') flash('Geçersiz e-posta veya şifre.', 'danger') else: # Admin girişi user = db.execute("SELECT * FROM kullanicilar WHERE kullanici_adi=? AND aktif=1", (giris,)).fetchone() if user and check_password_hash(user['sifre'], sifre): session['uid'] = user['id'] session['ad_soyad'] = user['ad_soyad'] session['giris_turu'] = 'admin' rol = db.execute("SELECT rol_adi FROM roller WHERE id=?", (user['rol_id'],)).fetchone() session['rol'] = rol['rol_adi'] if rol else '' return redirect('/firma-admin/istatistikler') flash('Geçersiz kullanıcı adı veya şifre.', 'danger') return render_template('login.html') @app.route('/cikis') def logout(): session.clear() return redirect(url_for('login')) @app.route('/kayit', methods=['GET', 'POST']) def kayit(): if request.method == 'POST': db = get_db() firma_adi = request.form.get('firma_adi', '').strip() yetkili_adi = request.form.get('yetkili_adi', '').strip() email = request.form.get('email', '').strip().lower() telefon = request.form.get('telefon', '').strip() adres = request.form.get('adres', '').strip() sehir = request.form.get('sehir', '').strip() sifre = request.form.get('sifre', '') sifre2 = request.form.get('sifre_tekrar', '') hatalar = [] if not firma_adi: hatalar.append('Firma adı gereklidir.') if not yetkili_adi: hatalar.append('Yetkili adı gereklidir.') if not email: hatalar.append('E-posta gereklidir.') if not sifre: hatalar.append('Şifre gereklidir.') if sifre != sifre2: hatalar.append('Şifreler eşleşmiyor.') if len(sifre) < 6: hatalar.append('Şifre en az 6 karakter olmalıdır.') logo_filename = None if 'logo' in request.files: logo = request.files['logo'] if logo.filename and allowed_file(logo.filename): ext = logo.filename.rsplit('.', 1)[1].lower() logo_filename = f"firma_{secrets.token_hex(8)}.{ext}" logo.save(os.path.join(UPLOAD_FOLDER, logo_filename)) if hatalar: for h in hatalar: flash(h, 'danger') else: try: hash_pw = generate_password_hash(sifre) db.execute("INSERT INTO firmalar (firma_adi, yetkili_adi, email, telefon, adres, sehir, sifre, logo) VALUES (?,?,?,?,?,?,?,?)", (firma_adi, yetkili_adi, email, telefon, adres, sehir, hash_pw, logo_filename)) db.commit() flash('Kayıt başarılı! Admin onayı sonrası giriş yapabilirsiniz.', 'success') return redirect(url_for('login')) except sqlite3.IntegrityError: flash('Bu e-posta adresi zaten kayıtlı.', 'danger') return render_template('kayit.html') @app.route('/depo') @login_required def depo(): db = get_db() stoklar = db.execute(""" SELECT u.id, u.urun_kodu, u.urun_adi, u.birim, COALESCE(SUM(CASE WHEN sh.hareket_tipi='giriş' THEN sh.miktar ELSE 0 END),0) as giris, COALESCE(SUM(CASE WHEN sh.hareket_tipi='çıkış' THEN sh.miktar ELSE 0 END),0) as cikis, COALESCE(SUM(CASE WHEN sh.hareket_tipi='giriş' THEN sh.miktar ELSE -sh.miktar END),0) as stok FROM urunler u LEFT JOIN stok_hareketleri sh ON u.id=sh.urun_id WHERE u.aktif=1 GROUP BY u.id ORDER BY u.urun_adi """).fetchall() toplam_stok = sum(s['stok'] for s in stoklar) kritik = sum(1 for s in stoklar if s['stok'] <= 0) return render_template('depo.html', stoklar=stoklar, toplam_stok=toplam_stok, kritik=kritik) ADMIN_SIFRE = 'admin2026' @app.route('/admin', methods=['GET', 'POST']) def admin(): if session.get('admin_giris') != True: if request.method == 'POST': sifre = request.form.get('sifre', '') if sifre == ADMIN_SIFRE: session['admin_giris'] = True return redirect(url_for('admin')) flash('Yanlış şifre!', 'danger') return render_template('admin/login.html') db = get_db() firmalar = db.execute("SELECT * FROM firmalar ORDER BY id DESC").fetchall() bekleyen = db.execute("SELECT COUNT(*) c FROM firmalar WHERE onay=0").fetchone()['c'] onayli = db.execute("SELECT COUNT(*) c FROM firmalar WHERE onay=1").fetchone()['c'] toplam = db.execute("SELECT COUNT(*) c FROM firmalar").fetchone()['c'] return render_template('admin/index.html', firmalar=firmalar, bekleyen=bekleyen, onayli=onayli, toplam=toplam) @app.route('/admin/firma//onay', methods=['POST']) def admin_firma_onay(id): if session.get('admin_giris') != True: return redirect(url_for('admin')) db = get_db() db.execute("UPDATE firmalar SET onay=1 WHERE id=?", (id,)) db.commit() flash('Firma onaylandı.', 'success') return redirect(url_for('admin')) @app.route('/admin/firma//pasif', methods=['POST']) def admin_firma_pasif(id): if session.get('admin_giris') != True: return redirect(url_for('admin')) db = get_db() db.execute("UPDATE firmalar SET aktif=0 WHERE id=?", (id,)) db.commit() flash('Firma pasif yapıldı.', 'success') return redirect(url_for('admin')) @app.route('/admin/firma//sil', methods=['POST']) def admin_firma_sil(id): if session.get('admin_giris') != True: return redirect(url_for('admin')) db = get_db() db.execute("DELETE FROM firmalar WHERE id=?", (id,)) db.commit() flash('Firma silindi.', 'success') return redirect(url_for('admin')) @app.route('/admin/firma//detay') def admin_firma_detay(id): if session.get('admin_giris') != True: return redirect(url_for('admin')) db = get_db() firma = db.execute("SELECT * FROM firmalar WHERE id=?", (id,)).fetchone() if not firma: return redirect(url_for('admin')) return render_template('admin/detay.html', firma=firma) @app.route('/admin/cikis') def admin_cikis(): session.pop('admin_giris', None) return redirect(url_for('admin')) @app.route('/firma-admin') def firma_admin(): if 'firma_id' not in session: return redirect(url_for('login')) return redirect('/firma-admin/istatistikler') @app.route('/firma-admin/istatistikler') def firma_istatistikler(): if 'firma_id' not in session and 'uid' not in session: return redirect(url_for('login')) db = get_db() if 'uid' in session and 'firma_id' not in session: firma = db.execute("SELECT id FROM firmalar WHERE onay=1 ORDER BY id LIMIT 1").fetchone() if firma: session['firma_id'] = firma['id'] else: return redirect(url_for('firma_eposta')) firma_id = session['firma_id'] firma = db.execute("SELECT * FROM firmalar WHERE id=?", (firma_id,)).fetchone() stats = { 'toplam_mail': db.execute("SELECT COUNT(*) c FROM mailler WHERE firma_id=?", (firma_id,)).fetchone()['c'], 'okunmamis': db.execute("SELECT COUNT(*) c FROM mailler WHERE firma_id=? AND tur='gelen' AND okundu=0", (firma_id,)).fetchone()['c'], 'gonderilen': db.execute("SELECT COUNT(*) c FROM mailler WHERE firma_id=? AND tur='gonderilen'", (firma_id,)).fetchone()['c'], 'musteri': db.execute("SELECT COUNT(*) c FROM musteriler WHERE firma_id=? AND aktif=1", (firma_id,)).fetchone()['c'], 'urun': db.execute("SELECT COUNT(*) c FROM urunler WHERE aktif=1").fetchone()['c'], 'siparis': db.execute("SELECT COUNT(*) c FROM siparisler").fetchone()['c'], } son_mailler = db.execute("SELECT * FROM mailler WHERE firma_id=? AND tur='gelen' ORDER BY tarih DESC LIMIT 5", (firma_id,)).fetchall() son_siparisler = db.execute("""SELECT s.*, m.firma_adi as musteri_adi FROM siparisler s LEFT JOIN musteriler m ON s.musteri_id=m.id ORDER BY s.id DESC LIMIT 5""").fetchall() aktif_uretim = db.execute("""SELECT ie.*, u.urun_adi FROM uretim_is_emirleri ie LEFT JOIN urunler u ON ie.urun_id=u.id WHERE ie.durum IN ('üretimde','beklemede') ORDER BY ie.id DESC LIMIT 5""").fetchall() return render_template('firma_admin/istatistikler.html', firma=firma, stats=stats, son_mailler=son_mailler, son_siparisler=son_siparisler, aktif_uretim=aktif_uretim) @app.route('/firma-admin/planlama') def firma_planlama(): if 'firma_id' not in session: return redirect(url_for('login')) db = get_db() firma_id = session['firma_id'] firma = db.execute("SELECT * FROM firmalar WHERE id=?", (firma_id,)).fetchone() modeller = db.execute("SELECT * FROM modeller WHERE firma_id=? ORDER BY id DESC", (firma_id,)).fetchall() return render_template('firma_admin/planlama.html', firma=firma, modeller=modeller) @app.route('/firma-admin/planlama/ekle', methods=['GET', 'POST']) def firma_model_ekle(): if 'firma_id' not in session: return redirect(url_for('login')) db = get_db() firma_id = session['firma_id'] firma = db.execute("SELECT * FROM firmalar WHERE id=?", (firma_id,)).fetchone() if request.method == 'POST': model_kodu = request.form.get('model_kodu', '').strip() model_adi = request.form.get('model_adi', '').strip() kategori = request.form.get('kategori', '').strip() renk = request.form.get('renk', '').strip() beden = request.form.get('beden', '').strip() kumas = request.form.get('kumas', '').strip() aciklama = request.form.get('aciklama', '').strip() bitis_tarihi = request.form.get('bitis_tarihi') or None if not model_kodu or not model_adi: flash('Model kodu ve adı gereklidir.', 'danger') else: db.execute("INSERT INTO modeller (firma_id, model_kodu, model_adi, kategori, renk, beden, kumas, aciklama, bitis_tarihi) VALUES (?,?,?,?,?,?,?,?,?)", (firma_id, model_kodu, model_adi, kategori, renk, beden, kumas, aciklama, bitis_tarihi)) db.commit() flash('Model eklendi.', 'success') return redirect(url_for('firma_planlama')) return render_template('firma_admin/model_ekle.html', firma=firma) @app.route('/firma-admin/planlama//durum', methods=['POST']) def firma_model_durum(id): if 'firma_id' not in session: return redirect(url_for('login')) db = get_db() yeni_durum = request.form.get('durum', '') db.execute("UPDATE modeller SET durum=? WHERE id=? AND firma_id=?", (yeni_durum, id, session['firma_id'])) db.commit() flash('Durum güncellendi.', 'success') return redirect(url_for('firma_planlama')) @app.route('/firma-admin/planlama//sil', methods=['POST']) def firma_model_sil(id): if 'firma_id' not in session: return redirect(url_for('login')) db = get_db() db.execute("DELETE FROM modeller WHERE id=? AND firma_id=?", (id, session['firma_id'])) db.commit() flash('Model silindi.', 'success') return redirect(url_for('firma_planlama')) @app.route('/firma-admin/musteriler') def firma_musteriler(): if 'firma_id' not in session: return redirect(url_for('login')) db = get_db() firma_id = session['firma_id'] firma = db.execute("SELECT * FROM firmalar WHERE id=?", (firma_id,)).fetchone() arama = request.args.get('arama', '').strip() if arama: musteriler = db.execute("""SELECT * FROM musteriler WHERE firma_id=? AND aktif=1 AND (firma_adi LIKE ? OR telefon LIKE ? OR email LIKE ? OR sehir LIKE ?) ORDER BY firma_adi""", (firma_id, f'%{arama}%', f'%{arama}%', f'%{arama}%', f'%{arama}%')).fetchall() else: musteriler = db.execute("SELECT * FROM musteriler WHERE firma_id=? AND aktif=1 ORDER BY firma_adi", (firma_id,)).fetchall() return render_template('firma_admin/musteriler.html', firma=firma, musteriler=musteriler, arama=arama) @app.route('/firma-admin/musteri-bul') def firma_musteri_bul(): if 'firma_id' not in session and 'uid' not in session: return redirect(url_for('login')) db = get_db() if 'uid' in session and 'firma_id' not in session: firma = db.execute("SELECT id FROM firmalar WHERE onay=1 ORDER BY id LIMIT 1").fetchone() if firma: session['firma_id'] = firma['id'] else: return redirect(url_for('firma_eposta')) firma_id = session['firma_id'] firma = db.execute("SELECT * FROM firmalar WHERE id=?", (firma_id,)).fetchone() arama = request.args.get('arama', '').strip() if arama: musteriler = db.execute("""SELECT * FROM musteriler WHERE firma_id=? AND aktif=1 AND (firma_adi LIKE ? OR telefon LIKE ? OR email LIKE ? OR sehir LIKE ? OR adres LIKE ? OR notlar LIKE ?) ORDER BY firma_adi""", (firma_id, f'%{arama}%', f'%{arama}%', f'%{arama}%', f'%{arama}%', f'%{arama}%', f'%{arama}%')).fetchall() else: musteriler = db.execute("SELECT * FROM musteriler WHERE firma_id=? AND aktif=1 ORDER BY firma_adi", (firma_id,)).fetchall() return render_template('firma_admin/musteri_bul.html', firma=firma, musteriler=musteriler, arama=arama) def email_ara_web(url): """Web sitesinden e-posta adresi arar""" if not url: return '' try: if not url.startswith('http'): url = 'http://' + url headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'} response = requests.get(url, headers=headers, timeout=5, allow_redirects=True) import re emails = re.findall(r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}', response.text) # Genel email adreslerini filtrele skip = ['@example', '@test', '@sentry', '@wix', '@google', '@facebook', '@instagram', '@twitter'] emails = [e for e in emails if not any(s in e.lower() for s in skip)] return emails[0] if emails else '' except: return '' @app.route('/firma-admin/musteri-bul/google', methods=['POST']) def firma_musteri_google(): if 'firma_id' not in session and 'uid' not in session: return jsonify({'hata': 'Giriş yapmalısınız'}) data = request.get_json() sorgu = data.get('sorgu', '').strip() sehir = data.get('sehir', '').strip() if not sorgu: return jsonify({'hata': 'Arama terimi gerekli'}) try: arama_terimi = f"{sorgu} {sehir}".strip() run_input = { 'searchStringsArray': [arama_terimi], 'maxCrawledPlacesPerSearch': 15, 'language': 'tr' } run = APIFY_CLIENT.actor('compass/crawler-google-places').call(run_input=run_input) sonuclar = [] for item in APIFY_CLIENT.dataset(run.default_dataset_id).iterate_items(): try: # Web sitesinden e-posta ara web_sitesi = item.get('website', '') email = '' if web_sitesi: email = email_ara_web(web_sitesi) sonuclar.append({ 'ad': item.get('title', ''), 'adres': item.get('address', ''), 'telefon': item.get('phone', '') or item.get('phoneUnformatted', ''), 'email': email, 'puan': str(item.get('totalScore', '')), 'web_sitesi': web_sitesi, 'kaynak': 'Google Maps' }) except Exception: continue return jsonify({'sonuclar': sonuclar[:15], 'toplam': len(sonuclar)}) except Exception as e: return jsonify({'hata': f'Arama hatası: {str(e)}'}) @app.route('/firma-admin/musteri-bul/linkedin', methods=['POST']) def firma_musteri_linkedin(): if 'firma_id' not in session and 'uid' not in session: return jsonify({'hata': 'Giriş yapmalısınız'}) data = request.get_json() sorgu = data.get('sorgu', '').strip() sehir = data.get('sehir', '').strip() if not sorgu: return jsonify({'hata': 'Arama terimi gerekli'}) try: arama_terimi = f"{sorgu} {sehir}".strip() # Apify Google Search Scraper kullanarak LinkedIn ara run_input = { 'queries': f'site:linkedin.com/company {arama_terimi}', 'maxPagesPerQuery': 1, 'languageCode': 'tr' } run = APIFY_CLIENT.actor('apify/google-search-scraper').call(run_input=run_input) sonuclar = [] for item in APIFY_CLIENT.dataset(run.default_dataset_id).iterate_items(): try: # Google sonuçlarından LinkedIn bilgilerini çıkar for result in item.get('organicResults', []): link = result.get('url', '') if 'linkedin.com/company' in link: baslik = result.get('title', '') aciklama = result.get('description', '') # Şirket adını temizle sirket_adi = baslik.split(' - ')[0].split(' | ')[0].strip() # LinkedIn sayfasından e-posta ara email = email_ara_web(link) # Açıklamadan da e-posta kontrolü if not email and aciklama: import re email_match = re.search(r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}', aciklama) if email_match: email = email_match.group(0) sonuclar.append({ 'ad': sirket_adi, 'aciklama': (aciklama or '')[:200], 'email': email, 'link': link, 'sektor': '', 'calisan_sayisi': '', 'konum': sehir, 'kaynak': 'LinkedIn' }) except Exception: continue return jsonify({'sonuclar': sonuclar[:15], 'toplam': len(sonuclar)}) except Exception as e: return jsonify({'hata': f'Arama hatası: {str(e)}'}) @app.route('/firma-admin/musteri-bul/kaydet', methods=['POST']) def firma_musteri_web_kaydet(): if 'firma_id' not in session and 'uid' not in session: return jsonify({'hata': 'Giriş yapmalısınız'}) db = get_db() firma_id = session.get('firma_id') if not firma_id and 'uid' in session: firma = db.execute("SELECT id FROM firmalar WHERE onay=1 ORDER BY id LIMIT 1").fetchone() firma_id = firma['id'] if firma else None if not firma_id: return jsonify({'hata': 'Firma bulunamadı'}) data = request.get_json() firma_adi = data.get('firma_adi', '').strip() telefon = data.get('telefon', '').strip() email_adres = data.get('email', '').strip() sehir = data.get('sehir', '').strip() adres = data.get('adres', '').strip() notlar = data.get('notlar', '').strip() kaynak = data.get('kaynak', '').strip() if not firma_adi: return jsonify({'hata': 'Firma adı gereklidir'}) # Benzersiz müşteri kodu oluştur musteri_kodu = f"MUS-{secrets.token_hex(4).upper()}" try: db.execute("""INSERT INTO musteriler (musteri_kodu, firma_adi, telefon, email, sehir, adres, notlar, firma_id) VALUES (?,?,?,?,?,?,?,?)""", (musteri_kodu, firma_adi, telefon, email_adres, sehir, adres, f"[{kaynak}] {notlar}" if notlar else f"Web'den eklendi: {kaynak}", firma_id)) db.commit() return jsonify({'basarili': True, 'mesaj': f'{firma_adi} müşteri olarak eklendi'}) except Exception as e: return jsonify({'hata': f'Kayıt hatası: {str(e)}'}) @app.route('/firma-admin/musteriler/ekle', methods=['GET', 'POST']) def firma_musteri_ekle(): if 'firma_id' not in session: return redirect(url_for('login')) db = get_db() firma_id = session['firma_id'] firma = db.execute("SELECT * FROM firmalar WHERE id=?", (firma_id,)).fetchone() if request.method == 'POST': firma_adi = request.form.get('firma_adi', '').strip() telefon = request.form.get('telefon', '').strip() email = request.form.get('email', '').strip() sehir = request.form.get('sehir', '').strip() adres = request.form.get('adres', '').strip() notlar = request.form.get('notlar', '').strip() if not firma_adi: flash('Müşteri adı gereklidir.', 'danger') else: db.execute("INSERT INTO musteriler (firma_id, firma_adi, telefon, email, sehir, adres, notlar) VALUES (?,?,?,?,?,?,?)", (firma_id, firma_adi, telefon, email, sehir, adres, notlar)) db.commit() flash('Müşteri eklendi.', 'success') return redirect(url_for('firma_musteriler')) return render_template('firma_admin/musteri_ekle.html', firma=firma) @app.route('/firma-admin/musteriler//duzenle', methods=['GET', 'POST']) def firma_musteri_duzenle(id): if 'firma_id' not in session: return redirect(url_for('login')) db = get_db() firma_id = session['firma_id'] firma = db.execute("SELECT * FROM firmalar WHERE id=?", (firma_id,)).fetchone() musteri = db.execute("SELECT * FROM musteriler WHERE id=? AND firma_id=?", (id, firma_id)).fetchone() if not musteri: return redirect(url_for('firma_musteriler')) if request.method == 'POST': firma_adi = request.form.get('firma_adi', '').strip() telefon = request.form.get('telefon', '').strip() email = request.form.get('email', '').strip() sehir = request.form.get('sehir', '').strip() adres = request.form.get('adres', '').strip() notlar = request.form.get('notlar', '').strip() db.execute("UPDATE musteriler SET firma_adi=?, telefon=?, email=?, sehir=?, adres=?, notlar=? WHERE id=? AND firma_id=?", (firma_adi, telefon, email, sehir, adres, notlar, id, firma_id)) db.commit() flash('Müşteri güncellendi.', 'success') return redirect(url_for('firma_musteriler')) return render_template('firma_admin/musteri_duzenle.html', firma=firma, musteri=musteri) @app.route('/firma-admin/musteriler//sil', methods=['POST']) def firma_musteri_sil(id): if 'firma_id' not in session: return redirect(url_for('login')) db = get_db() db.execute("UPDATE musteriler SET aktif=0 WHERE id=? AND firma_id=?", (id, session['firma_id'])) db.commit() flash('Müşteri silindi.', 'success') return redirect(url_for('firma_musteriler')) # ─── Mail Fonksiyonları ───────────────────────────────────────── def mail_ayarlarini_al(firma_id): db = get_db() return db.execute("SELECT * FROM mail_ayarlar WHERE firma_id=?", (firma_id,)).fetchone() import re def mail_adres_cikar(text): """'Name ' formatından sadece e-posta adresini çıkarır""" if not text: return text # formatında mı? match = re.search(r'<([^>]+)>', text) if match: return match.group(1).strip() # Doğrudan e-posta mı? if '@' in text and ' ' not in text.strip(): return text.strip() return text.strip() def mail_gonder(firma_id, alici, konu, icerik, dosyalar=None): ayarlar = mail_ayarlarini_al(firma_id) if not ayarlar: return False, "Mail ayarları yapılmamış. Lütfen ayarları tamamlayın." try: from email.mime.base import MIMEBase from email import encoders # Alıcı e-posta adresini temizle alici_email = mail_adres_cikar(alici) msg = MIMEMultipart() msg['From'] = f"{ayarlar['kullanici_adi'] or ''} <{ayarlar['e_posta']}>" msg['To'] = alici_email msg['Subject'] = konu msg.attach(MIMEText(icerik, 'plain', 'utf-8')) # Dosyaları ekle uploads_klasoru = os.path.join(os.path.dirname(__file__), 'static', 'uploads', 'mail_ekleri') if dosyalar: for dosya in dosyalar: dosya_yolu = os.path.join(uploads_klasoru, dosya['dosya_adi']) if os.path.exists(dosya_yolu): with open(dosya_yolu, 'rb') as f: part = MIMEBase('application', 'octet-stream') part.set_payload(f.read()) encoders.encode_base64(part) part.add_header('Content-Disposition', f'attachment; filename="{dosya["orijinal_adi"]}"') msg.attach(part) port = ayarlar['smtp_port'] if port == 465: server = smtplib.SMTP_SSL(ayarlar['smtp_sunucu'], port, timeout=30) else: server = smtplib.SMTP(ayarlar['smtp_sunucu'], port, timeout=30) server.ehlo() server.starttls() server.ehlo() server.login(ayarlar['e_posta'], ayarlar['sifre']) server.sendmail(ayarlar['e_posta'], alici_email, msg.as_string()) server.quit() return True, "Mail başarıyla gönderildi." except smtplib.SMTPAuthenticationError as e: error_msg = str(e) if '535' in error_msg: return False, "Doğrulama hatası! Lütfen şifrenizi kontrol edin." return False, f"SMTP doğrulama hatası: {error_msg}" except smtplib.SMTPConnectError as e: return False, f"SMTP sunucusuna bağlanamadı: {str(e)}" except smtplib.SMTPException as e: return False, f"SMTP hatası: {str(e)}" except Exception as e: return False, f"Beklenmeyen hata: {str(e)}" def tarih_duzenle(tarih_str): """Email tarihini standart YYYY-MM-DD HH:MM:SS formatına çevirir""" if not tarih_str: return '' try: dt = parsedate_to_datetime(tarih_str) return dt.strftime('%Y-%m-%d %H:%M:%S') except Exception: return tarih_str def mail_cek(firma_id): ayarlar = mail_ayarlarini_al(firma_id) if not ayarlar: return 0 protokol = ayarlar['alma_protokolu'] if ayarlar['alma_protokolu'] else 'imap' try: if protokol == 'pop3': import poplib mail = poplib.POP3_SSL(ayarlar['pop3_sunucu'], ayarlar['pop3_port']) mail.user(ayarlar['e_posta']) mail.pass_(ayarlar['sifre']) mesaj_sayisi, _ = mail.stat() yeni_adet = 0 db = get_db() baslangic = max(1, mesaj_sayisi - 99) for i in range(baslangic, mesaj_sayisi + 1): try: _, satirlar, _ = mail.retr(i) msg_bytes = b'\r\n'.join(satirlar) msg = email.message_from_bytes(msg_bytes) konu = msg['Subject'] or '(Konu yok)' if konu: decoded = decode_header(konu) konu_parcalari = [] for part, enc in decoded: if isinstance(part, bytes): konu_parcalari.append(part.decode(enc or 'utf-8', errors='ignore')) else: konu_parcalari.append(part) konu = ''.join(konu_parcalari) gonderen = msg['From'] or 'Bilinmeyen' tarih = tarih_duzenle(msg['Date'] or '') icerik = "" if msg.is_multipart(): for part in msg.walk(): if part.get_content_type() == 'text/plain': icerik = part.get_payload(decode=True).decode('utf-8', errors='ignore') break else: icerik = msg.get_payload(decode=True).decode('utf-8', errors='ignore') mevcut = db.execute("SELECT id FROM mailler WHERE firma_id=? AND gonderen=? AND konu=? AND tur='gelen'", (firma_id, gonderen, konu)).fetchone() if not mevcut: db.execute("INSERT INTO mailler (firma_id, gonderen, alici, konu, icerik, tur, tarih) VALUES (?,?,?,?,?,'gelen',?)", (firma_id, gonderen, ayarlar['e_posta'], konu, icerik, tarih)) yeni_adet += 1 except Exception: continue db.commit() mail.quit() return yeni_adet else: # IMAP ile TÜM mailleri çek mail = imaplib.IMAP4_SSL(ayarlar['imap_sunucu'], ayarlar['imap_port']) mail.login(ayarlar['e_posta'], ayarlar['sifre']) mail.select('INBOX') # TÜM mailleri ara (sadece okunmamış değil) status, messages = mail.search(None, 'ALL') if status != 'OK': return 0 mail_ids = messages[0].split() yeni_adet = 0 db = get_db() # Son 100 maili çek (performans için) for mid in mail_ids[-100:]: try: status, msg_data = mail.fetch(mid, '(RFC822)') if status != 'OK': continue msg = email.message_from_bytes(msg_data[0][1]) konu = msg['Subject'] or '(Konu yok)' if konu: decoded = decode_header(konu) konu_parcalari = [] for part, enc in decoded: if isinstance(part, bytes): konu_parcalari.append(part.decode(enc or 'utf-8', errors='ignore')) else: konu_parcalari.append(part) konu = ''.join(konu_parcalari) gonderen = msg['From'] or 'Bilinmeyen' tarih = tarih_duzenle(msg['Date'] or '') icerik = "" if msg.is_multipart(): for part in msg.walk(): if part.get_content_type() == 'text/plain': payload = part.get_payload(decode=True) if payload: icerik = payload.decode('utf-8', errors='ignore') break else: payload = msg.get_payload(decode=True) if payload: icerik = payload.decode('utf-8', errors='ignore') mevcut = db.execute("SELECT id FROM mailler WHERE firma_id=? AND gonderen=? AND konu=? AND tur='gelen'", (firma_id, gonderen, konu)).fetchone() if not mevcut: db.execute("INSERT INTO mailler (firma_id, gonderen, alici, konu, icerik, tur, tarih) VALUES (?,?,?,?,?,'gelen',?)", (firma_id, gonderen, ayarlar['e_posta'], konu, icerik, tarih)) yeni_adet += 1 except Exception as e: continue db.commit() mail.logout() return yeni_adet except Exception as e: print(f"Mail çekme hatası: {e}") return 0 @app.route('/firma-admin/mail-ayarlari', methods=['GET', 'POST']) def firma_mail_ayarlari(): if 'firma_id' not in session: return redirect(url_for('login')) db = get_db() firma_id = session['firma_id'] firma = db.execute("SELECT * FROM firmalar WHERE id=?", (firma_id,)).fetchone() ayarlar = db.execute("SELECT * FROM mail_ayarlar WHERE firma_id=?", (firma_id,)).fetchone() if request.method == 'POST': smtp_sunucu = request.form.get('smtp_sunucu', 'smtp.gmail.com').strip() smtp_port = int(request.form.get('smtp_port', 587)) imap_sunucu = request.form.get('imap_sunucu', '').strip() imap_port = int(request.form.get('imap_port', 993)) pop3_sunucu = request.form.get('pop3_sunucu', '').strip() pop3_port = int(request.form.get('pop3_port', 995)) alma_protokolu = request.form.get('alma_protokolu', 'imap').strip() e_posta = request.form.get('e_posta', '').strip() sifre = request.form.get('sifre', '').strip() kullanici_adi = request.form.get('kullanici_adi', '').strip() if not e_posta or not sifre: flash('E-posta ve şifre gereklidir.', 'danger') else: if ayarlar: db.execute("""UPDATE mail_ayarlar SET smtp_sunucu=?, smtp_port=?, imap_sunucu=?, imap_port=?, pop3_sunucu=?, pop3_port=?, alma_protokolu=?, e_posta=?, sifre=?, kullanici_adi=? WHERE firma_id=?""", (smtp_sunucu, smtp_port, imap_sunucu, imap_port, pop3_sunucu, pop3_port, alma_protokolu, e_posta, sifre, kullanici_adi, firma_id)) else: db.execute("""INSERT INTO mail_ayarlar (firma_id, smtp_sunucu, smtp_port, imap_sunucu, imap_port, pop3_sunucu, pop3_port, alma_protokolu, e_posta, sifre, kullanici_adi) VALUES (?,?,?,?,?,?,?,?,?,?,?)""", (firma_id, smtp_sunucu, smtp_port, imap_sunucu, imap_port, pop3_sunucu, pop3_port, alma_protokolu, e_posta, sifre, kullanici_adi)) db.commit() flash('Mail ayarları kaydedildi.', 'success') return redirect(url_for('firma_mail_ayarlari')) return render_template('firma_admin/mail_ayarlari.html', firma=firma, ayarlar=ayarlar) @app.route('/firma-admin/mail-cek') def firma_mail_cek(): if 'firma_id' not in session and 'uid' not in session: return redirect(url_for('login')) db = get_db() if 'uid' in session and 'firma_id' not in session: firma = db.execute("SELECT id FROM firmalar WHERE onay=1 ORDER BY id LIMIT 1").fetchone() if firma: session['firma_id'] = firma['id'] else: flash('Firma bulunamadı.', 'warning') return redirect(url_for('firma_eposta')) yeni = mail_cek(session['firma_id']) if yeni > 0: flash(f'{yeni} yeni mail alındı.', 'success') else: flash('Yeni mail bulunamadı veya zaten tüm mailler çekilmiş.', 'info') return redirect(url_for('firma_eposta')) @app.route('/firma-admin/mail-test') def firma_mail_test(): if 'firma_id' not in session: return redirect(url_for('login')) db = get_db() firma_id = session['firma_id'] ayarlar = db.execute("SELECT * FROM mail_ayarlar WHERE firma_id=?", (firma_id,)).fetchone() if not ayarlar: flash('Önce mail ayarlarını yapın.', 'danger') return redirect(url_for('firma_mail_ayarlari')) alici = ayarlar['e_posta'] konu = 'Kolay Takip - Test Maili' icerik = f"""Merhaba, Bu bir test mailidir. Mail ayarlarınız doğru çalışmaktadır. Gönderen: {ayarlar['e_posta']} SMTP Sunucu: {ayarlar['smtp_sunucu']}:{ayarlar['smtp_port']} IMAP Sunucu: {ayarlar['imap_sunucu']}:{ayarlar['imap_port']} Saygılarımızla, Kolay Takip Ekibi """ basarili, mesaj = mail_gonder(firma_id, alici, konu, icerik) if basarili: flash(f'Test maili başarıyla gönderildi! {alici} adresini kontrol edin.', 'success') else: flash(f'Test maili gönderilemedi: {mesaj}', 'danger') return redirect(url_for('firma_mail_ayarlari')) # ─── İletişim Sayfaları ───────────────────────────────────────── @app.route('/firma-admin/iletisim') def firma_iletisim(): if 'firma_id' not in session: return redirect(url_for('login')) db = get_db() firma_id = session['firma_id'] firma = db.execute("SELECT * FROM firmalar WHERE id=?", (firma_id,)).fetchone() klasor = request.args.get('klasor', 'gelen') if klasor == 'gonderilen': mailler = db.execute("SELECT * FROM mailler WHERE firma_id=? AND tur='gonderilen' ORDER BY tarih DESC", (firma_id,)).fetchall() elif klasor == 'taslak': mailler = db.execute("SELECT * FROM mailler WHERE firma_id=? AND tur='taslak' ORDER BY tarih DESC", (firma_id,)).fetchall() else: mailler = db.execute("SELECT * FROM mailler WHERE firma_id=? AND tur='gelen' ORDER BY tarih DESC", (firma_id,)).fetchall() okunmamis = db.execute("SELECT COUNT(*) c FROM mailler WHERE firma_id=? AND tur='gelen' AND okundu=0", (firma_id,)).fetchone()['c'] return render_template('firma_admin/iletisim.html', firma=firma, mailler=mailler, klasor=klasor, okunmamis=okunmamis) @app.route('/firma-admin/iletisim/yeni', methods=['GET', 'POST']) def firma_mail_yaz(): if 'firma_id' not in session: return redirect(url_for('login')) db = get_db() firma_id = session['firma_id'] firma = db.execute("SELECT * FROM firmalar WHERE id=?", (firma_id,)).fetchone() musteriler = db.execute("SELECT * FROM musteriler WHERE firma_id=? AND aktif=1 ORDER BY firma_adi", (firma_id,)).fetchall() # Mail ayarlarını al - gönderen olarak kullan mail_ayarlari = db.execute("SELECT * FROM mail_ayarlar WHERE firma_id=?", (firma_id,)).fetchone() gonderen_email = mail_ayarlari['e_posta'] if mail_ayarlari else firma['email'] gonderen_adi = mail_ayarlari['kullanici_adi'] if mail_ayarlari and mail_ayarlari['kullanici_adi'] else firma['firma_adi'] if not mail_ayarlari: flash('Önce mail ayarlarını yapın.', 'warning') return redirect(url_for('firma_mail_ayarlari')) if request.method == 'POST': alici = request.form.get('alici', '').strip() konu = request.form.get('konu', '').strip() icerik = request.form.get('icerik', '').strip() islem = request.form.get('islem', 'gonder') if not alici or not konu: flash('Alıcı ve konu gereklidir.', 'danger') else: if islem == 'taslak': db.execute("INSERT INTO mailler (firma_id, gonderen, alici, konu, icerik, tur) VALUES (?,?,?,?,?,?)", (firma_id, gonderen_email, alici, konu, icerik, 'taslak')) db.commit() flash('Taslak olarak kaydedildi.', 'success') else: # Gerçek SMTP ile gönder basarili, mesaj = mail_gonder(firma_id, alici, konu, icerik) db.execute("INSERT INTO mailler (firma_id, gonderen, alici, konu, icerik, tur) VALUES (?,?,?,?,?,?)", (firma_id, gonderen_email, alici, konu, icerik, 'gonderilen')) db.commit() if basarili: flash(mesaj, 'success') else: flash(mesaj, 'danger') return redirect(url_for('firma_iletisim')) # URL'den alici parametresi varsa doldur alici = request.args.get('alici', '') konu = request.args.get('konu', '') return render_template('firma_admin/mail_yaz.html', firma=firma, musteriler=musteriler, alici=alici, konu=konu, gonderen_email=gonderen_email) @app.route('/firma-admin/iletisim/') def firma_mail_detay(id): if 'firma_id' not in session: return redirect(url_for('login')) db = get_db() firma_id = session['firma_id'] firma = db.execute("SELECT * FROM firmalar WHERE id=?", (firma_id,)).fetchone() mail = db.execute("SELECT * FROM mailler WHERE id=? AND firma_id=?", (id, firma_id)).fetchone() if not mail: return redirect(url_for('firma_iletisim')) # Okundu olarak işaretle if mail['tur'] == 'gelen' and not mail['okundu']: db.execute("UPDATE mailler SET okundu=1 WHERE id=?", (id,)) db.commit() return render_template('firma_admin/mail_detay.html', firma=firma, mail=mail) @app.route('/firma-admin/iletisim//sil', methods=['POST']) def firma_mail_sil(id): if 'firma_id' not in session: return redirect(url_for('login')) db = get_db() db.execute("DELETE FROM mailler WHERE id=? AND firma_id=?", (id, session['firma_id'])) db.commit() flash('Mail silindi.', 'success') return redirect(url_for('firma_iletisim')) # ─── E-Posta Sayfası ───────────────────────────────────────── @app.route('/firma-admin/eposta') def firma_eposta(): if 'firma_id' not in session and 'uid' not in session: return redirect(url_for('login')) db = get_db() # Admin ise ilk firmaya yönlendir if 'uid' in session and 'firma_id' not in session: firma = db.execute("SELECT * FROM firmalar WHERE onay=1 ORDER BY id LIMIT 1").fetchone() if firma: session['firma_id'] = firma['id'] session['firma_adi'] = firma['firma_adi'] session['yetkili'] = firma['yetkili_adi'] session['firma_logo'] = firma['logo'] session['giris_turu'] = 'firma' else: flash('Henüz onaylı firma bulunmuyor.', 'warning') return redirect(url_for('firma_eposta')) firma_id = session['firma_id'] firma = db.execute("SELECT * FROM firmalar WHERE id=?", (firma_id,)).fetchone() klasor = request.args.get('klasor', 'gelen') arama = request.args.get('arama', '').strip() # Klasöre göre filtrele if klasor == 'tumu': if arama: mailler = db.execute("SELECT * FROM mailler WHERE firma_id=? AND (konu LIKE ? OR icerik LIKE ? OR gonderen LIKE ? OR alici LIKE ?) ORDER BY tarih DESC", (firma_id, f'%{arama}%', f'%{arama}%', f'%{arama}%', f'%{arama}%')).fetchall() else: mailler = db.execute("SELECT * FROM mailler WHERE firma_id=? ORDER BY tarih DESC", (firma_id,)).fetchall() elif klasor == 'gonderilen': if arama: mailler = db.execute("SELECT * FROM mailler WHERE firma_id=? AND tur='gonderilen' AND (konu LIKE ? OR icerik LIKE ? OR alici LIKE ?) ORDER BY tarih DESC", (firma_id, f'%{arama}%', f'%{arama}%', f'%{arama}%')).fetchall() else: mailler = db.execute("SELECT * FROM mailler WHERE firma_id=? AND tur='gonderilen' ORDER BY tarih DESC", (firma_id,)).fetchall() elif klasor == 'taslak': if arama: mailler = db.execute("SELECT * FROM mailler WHERE firma_id=? AND tur='taslak' AND (konu LIKE ? OR icerik LIKE ? OR alici LIKE ?) ORDER BY tarih DESC", (firma_id, f'%{arama}%', f'%{arama}%', f'%{arama}%')).fetchall() else: mailler = db.execute("SELECT * FROM mailler WHERE firma_id=? AND tur='taslak' ORDER BY tarih DESC", (firma_id,)).fetchall() else: # gelen - sadece okunmamış mailler if arama: mailler = db.execute("SELECT * FROM mailler WHERE firma_id=? AND tur='gelen' AND okundu=0 AND (konu LIKE ? OR icerik LIKE ? OR gonderen LIKE ?) ORDER BY tarih DESC", (firma_id, f'%{arama}%', f'%{arama}%', f'%{arama}%')).fetchall() else: mailler = db.execute("SELECT * FROM mailler WHERE firma_id=? AND tur='gelen' AND okundu=0 ORDER BY tarih DESC", (firma_id,)).fetchall() # İstatistikler gelen_sayisi = db.execute("SELECT COUNT(*) c FROM mailler WHERE firma_id=? AND tur='gelen' AND okundu=0", (firma_id,)).fetchone()['c'] gonderilen_sayisi = db.execute("SELECT COUNT(*) c FROM mailler WHERE firma_id=? AND tur='gonderilen'", (firma_id,)).fetchone()['c'] okunmamis_sayisi = db.execute("SELECT COUNT(*) c FROM mailler WHERE firma_id=? AND tur='gelen' AND okundu=0", (firma_id,)).fetchone()['c'] taslak_sayisi = db.execute("SELECT COUNT(*) c FROM mailler WHERE firma_id=? AND tur='taslak'", (firma_id,)).fetchone()['c'] mail_ayarlar = db.execute("SELECT * FROM mail_ayarlar WHERE firma_id=?", (firma_id,)).fetchone() toplam_sayisi = gelen_sayisi + gonderilen_sayisi + taslak_sayisi return render_template('firma_admin/eposta.html', firma=firma, mailler=mailler, klasor=klasor, arama=arama, gelen_sayisi=gelen_sayisi, gonderilen_sayisi=gonderilen_sayisi, okunmamis_sayisi=okunmamis_sayisi, taslak_sayisi=taslak_sayisi, toplam_sayisi=toplam_sayisi, mail_ayarlar=mail_ayarlar) @app.route('/firma-admin/eposta/cek') def firma_eposta_cek(): if 'firma_id' not in session and 'uid' not in session: return jsonify({'yeni': 0, 'toplam': 0}) firma_id = session.get('firma_id') if not firma_id and 'uid' in session: firma = get_db().execute("SELECT id FROM firmalar WHERE onay=1 ORDER BY id LIMIT 1").fetchone() firma_id = firma['id'] if firma else None if not firma_id: return jsonify({'yeni': 0, 'toplam': 0}) yeni = mail_cek(firma_id) db = get_db() toplam = db.execute("SELECT COUNT(*) c FROM mailler WHERE firma_id=? AND tur='gelen'", (firma_id,)).fetchone()['c'] okunmamis = db.execute("SELECT COUNT(*) c FROM mailler WHERE firma_id=? AND tur='gelen' AND okundu=0", (firma_id,)).fetchone()['c'] return jsonify({'yeni': yeni, 'toplam': toplam, 'okunmamis': okunmamis}) @app.route('/firma-admin/eposta/durum') def firma_eposta_durum(): if 'firma_id' not in session and 'uid' not in session: return jsonify({'bagli': False, 'mesaj': 'Giriş yapılmamış'}) db = get_db() firma_id = session.get('firma_id') if not firma_id and 'uid' in session: firma = db.execute("SELECT id FROM firmalar WHERE onay=1 ORDER BY id LIMIT 1").fetchone() firma_id = firma['id'] if firma else None if not firma_id: return jsonify({'bagli': False, 'mesaj': 'Firma bulunamadı'}) ayarlar = db.execute("SELECT * FROM mail_ayarlar WHERE firma_id=?", (firma_id,)).fetchone() if not ayarlar: return jsonify({'bagli': False, 'mesaj': 'Mail ayarları yapılmamış', 'eposta': None}) # SMTP bağlantısını test et try: if ayarlar['smtp_port'] == 465: server = smtplib.SMTP_SSL(ayarlar['smtp_sunucu'], ayarlar['smtp_port'], timeout=8) else: server = smtplib.SMTP(ayarlar['smtp_sunucu'], ayarlar['smtp_port'], timeout=8) server.ehlo() server.starttls() server.ehlo() server.login(ayarlar['e_posta'], ayarlar['sifre']) server.quit() return jsonify({ 'bagli': True, 'mesaj': 'Bağlantı aktif', 'eposta': ayarlar['e_posta'], 'smtp': ayarlar['smtp_sunucu'], 'smtp_port': ayarlar['smtp_port'], 'imap': ayarlar['imap_sunucu'], 'imap_port': ayarlar['imap_port'] }) except Exception as e: return jsonify({ 'bagli': False, 'mesaj': f'Bağlantı hatası: {str(e)}', 'eposta': ayarlar['e_posta'], 'smtp': ayarlar['smtp_sunucu'], 'smtp_port': ayarlar['smtp_port'] }) @app.route('/firma-admin/eposta/ai-olustur', methods=['POST']) def firma_eposta_ai_olustur(): if 'firma_id' not in session and 'uid' not in session: return jsonify({'hata': 'Giriş yapmalısınız'}) data = request.get_json() alici = data.get('alici', '').strip() konu = data.get('konu', '').strip() talimat = data.get('talimat', '').strip() tur = data.get('tur', 'genel') # genel, teklif, tesekkur, Hatirlatma, vb. if not talimat: return jsonify({'hata': 'Talimat gerekli'}) try: # Müşteri bilgilerini çek db = get_db() firma_id = session.get('firma_id') if not firma_id and 'uid' in session: firma = db.execute("SELECT id FROM firmalar WHERE onay=1 ORDER BY id LIMIT 1").fetchone() firma_id = firma['id'] if firma else None firma_bilgi = '' if firma_id: f = db.execute("SELECT * FROM firmalar WHERE id=?", (firma_id,)).fetchone() if f: firma_bilgi = f"Firma: {f['firma_adi']}, Yetkili: {f['yetkili_adi']}" # Müşteri bilgisi musteri_bilgi = '' if alici: m = db.execute("SELECT * FROM musteriler WHERE email=? OR firma_adi LIKE ?", (alici, f'%{alici}%')).fetchone() if m: musteri_bilgi = f"Müşteri: {m['firma_adi']}, Telefon: {m['telefon'] or 'Yok'}, Şehir: {m['sehir'] or 'Yok'}" # Mail türüne göre prompt oluştur tur_aciklamalari = { 'genel': 'Profesyonel bir iş maili', 'teklif': 'Ürün veya hizmet teklifi içeren pazarlama maili', 'tesekkur': 'Teşekkür ve minnettarlık bildiren mail', 'hatirlatma': 'Hatırlatma ve takip maili', 'satis': 'Satış odaklı ikna edici mail', 'bilgilendirme': 'Bilgilendirme ve güncelleme maili' } prompt = f"""Sen profesyonel bir e-posta yazma asistanısın. Aşağıdaki bilgilere göre Türkçe bir e-posta yaz. Gönderen: {firma_bilgi} Alıcı: {musteri_bilgi or alici} Konu: {konu or 'Belirtilmemiş'} Mail Türü: {tur_aciklamalari.get(tur, tur)} Talimat: {talimat} Kurallar: 1. Profesyonel ve saygın bir dil kullan 2. Kısa ve öz ol (maksimum 200 kelime) 3. Net bir çağrı (call-to-action) ekle 4. HTML formatında yazma, düz metin olarak yaz 5. Selamlama ve kapanış ekle Maili sadece içeriği olarak yaz, konu ve selamlama hariç başka bir başlık ekleme.""" response = GEMINI_CLIENT.models.generate_content(model='gemini-2.0-flash-lite', contents=prompt) icerik = response.text return jsonify({ 'basarili': True, 'icerik': icerik, 'konu': konu or 'Konu' }) except Exception as e: return jsonify({'hata': f'AI hatası: {str(e)}'}) @app.route('/firma-admin/eposta/ekle', methods=['GET', 'POST']) def firma_eposta_ekle(): if 'firma_id' not in session and 'uid' not in session: return redirect(url_for('login')) db = get_db() # Admin ise ilk firmaya yönlendir if 'uid' in session and 'firma_id' not in session: firma = db.execute("SELECT * FROM firmalar WHERE onay=1 ORDER BY id LIMIT 1").fetchone() if firma: session['firma_id'] = firma['id'] session['firma_adi'] = firma['firma_adi'] session['yetkili'] = firma['yetkili_adi'] session['firma_logo'] = firma['logo'] session['giris_turu'] = 'firma' else: flash('Henüz onaylı firma bulunmuyor.', 'warning') return redirect(url_for('firma_eposta')) firma_id = session['firma_id'] firma = db.execute("SELECT * FROM firmalar WHERE id=?", (firma_id,)).fetchone() musteriler = db.execute("SELECT * FROM musteriler WHERE firma_id=? AND aktif=1 ORDER BY firma_adi", (firma_id,)).fetchall() mail_ayarlari = db.execute("SELECT * FROM mail_ayarlar WHERE firma_id=?", (firma_id,)).fetchone() gonderen_email = mail_ayarlari['e_posta'] if mail_ayarlari else firma['email'] if request.method == 'POST': alici = request.form.get('alici', '').strip() konu = request.form.get('konu', '').strip() icerik = request.form.get('icerik', '').strip() islem = request.form.get('islem', 'gonder') if not alici or not konu: flash('Alıcı ve konu gereklidir.', 'danger') else: # Dosyaları kaydet dosya_yollari = [] uploads_klasoru = os.path.join(app.config['UPLOAD_FOLDER'], 'mail_ekleri') os.makedirs(uploads_klasoru, exist_ok=True) dosyalar = request.files.getlist('dosyalar') for dosya in dosyalar: if dosya and dosya.filename: orijinal_adi = secure_filename(dosya.filename) # Benzersiz isim oluştur dosya_adi = f"mail_{firma_id}_{secrets.token_hex(8)}_{orijinal_adi}" dosya_kayit = os.path.join(uploads_klasoru, dosya_adi) dosya.save(dosya_kayit) dosya_yollari.append({ 'dosya_adi': dosya_adi, 'orijinal_adi': orijinal_adi, 'boyut': os.path.getsize(dosya_kayit), 'tur': dosya.content_type }) if islem == 'taslak': cursor = db.execute("INSERT INTO mailler (firma_id, gonderen, alici, konu, icerik, tur) VALUES (?,?,?,?,?,?)", (firma_id, gonderen_email, alici, konu, icerik, 'taslak')) mail_id = cursor.lastrowid # Ekleri kaydet for d in dosya_yollari: db.execute("INSERT INTO mail_ekleri (mail_id, dosya_adi, orijinal_adi, dosya_boyutu, dosya_turu) VALUES (?,?,?,?,?)", (mail_id, d['dosya_adi'], d['orijinal_adi'], d['boyut'], d['tur'])) db.commit() flash('Taslak olarak kaydedildi.', 'success') else: basarili, mesaj = mail_gonder(firma_id, alici, konu, icerik, dosya_yollari) cursor = db.execute("INSERT INTO mailler (firma_id, gonderen, alici, konu, icerik, tur) VALUES (?,?,?,?,?,?)", (firma_id, gonderen_email, alici, konu, icerik, 'gonderilen')) mail_id = cursor.lastrowid # Ekleri kaydet for d in dosya_yollari: db.execute("INSERT INTO mail_ekleri (mail_id, dosya_adi, orijinal_adi, dosya_boyutu, dosya_turu) VALUES (?,?,?,?,?)", (mail_id, d['dosya_adi'], d['orijinal_adi'], d['boyut'], d['tur'])) db.commit() if basarili: flash(mesaj + f" ({len(dosya_yollari)} ek ile)" if dosya_yollari else mesaj, 'success') else: flash(mesaj, 'danger') return redirect(url_for('firma_eposta')) alici = request.args.get('alici', '') konu = request.args.get('konu', '') return render_template('firma_admin/eposta_ekle.html', firma=firma, musteriler=musteriler, alici=alici, konu=konu, gonderen_email=gonderen_email) @app.route('/firma-admin/eposta/detay/') def firma_eposta_detay(id): if 'firma_id' not in session and 'uid' not in session: return jsonify({'error': 'Giriş yapmalısınız'}), 401 db = get_db() firma_id = session.get('firma_id') if not firma_id and 'uid' in session: firma = db.execute("SELECT id FROM firmalar WHERE onay=1 ORDER BY id LIMIT 1").fetchone() firma_id = firma['id'] if firma else None if not firma_id: return jsonify({'error': 'Firma bulunamadı'}), 404 mail = db.execute("SELECT * FROM mailler WHERE id=? AND firma_id=?", (id, firma_id)).fetchone() if not mail: return jsonify({'error': 'Mail bulunamadı'}), 404 # Okundu olarak işaretle if mail['tur'] == 'gelen' and not mail['okundu']: db.execute("UPDATE mailler SET okundu=1 WHERE id=?", (id,)) db.commit() # Ekleri al ekler = db.execute("SELECT * FROM mail_ekleri WHERE mail_id=?", (id,)).fetchall() ek_listesi = [] for ek in ekler: ek_listesi.append({ 'id': ek['id'], 'dosya_adi': ek['dosya_adi'], 'orijinal_adi': ek['orijinal_adi'], 'boyut': ek['dosya_boyutu'], 'tur': ek['dosya_turu'] }) return jsonify({ 'id': mail['id'], 'gonderen': mail['gonderen'], 'alici': mail['alici'], 'konu': mail['konu'], 'icerik': mail['icerik'], 'tur': mail['tur'], 'tarih': mail['tarih'], 'ekler': ek_listesi }) @app.route('/firma-admin/eposta/sil/') def firma_eposta_sil(id): if 'firma_id' not in session and 'uid' not in session: return redirect(url_for('login')) db = get_db() firma_id = session.get('firma_id') if not firma_id and 'uid' in session: firma = db.execute("SELECT id FROM firmalar WHERE onay=1 ORDER BY id LIMIT 1").fetchone() firma_id = firma['id'] if firma else None if not firma_id: return redirect(url_for('login')) db.execute("DELETE FROM mailler WHERE id=? AND firma_id=?", (id, firma_id)) db.commit() flash('Mail silindi.', 'success') return redirect(url_for('firma_eposta')) @app.route('/firma-admin/eposta/ayarlar', methods=['GET', 'POST']) def firma_eposta_ayarlar(): if 'firma_id' not in session and 'uid' not in session: return redirect(url_for('login')) db = get_db() # Admin ise ilk firmaya yönlendir if 'uid' in session and 'firma_id' not in session: firma = db.execute("SELECT * FROM firmalar WHERE onay=1 ORDER BY id LIMIT 1").fetchone() if firma: session['firma_id'] = firma['id'] session['firma_adi'] = firma['firma_adi'] session['yetkili'] = firma['yetkili_adi'] session['firma_logo'] = firma['logo'] session['giris_turu'] = 'firma' else: flash('Henüz onaylı firma bulunmuyor.', 'warning') return redirect(url_for('firma_eposta')) firma_id = session['firma_id'] firma = db.execute("SELECT * FROM firmalar WHERE id=?", (firma_id,)).fetchone() ayarlar = db.execute("SELECT * FROM mail_ayarlar WHERE firma_id=?", (firma_id,)).fetchone() if request.method == 'POST': smtp_sunucu = request.form.get('smtp_sunucu', 'smtp.gmail.com').strip() smtp_port = int(request.form.get('smtp_port', 587)) imap_sunucu = request.form.get('imap_sunucu', '').strip() imap_port = int(request.form.get('imap_port', 993)) pop3_sunucu = request.form.get('pop3_sunucu', '').strip() pop3_port = int(request.form.get('pop3_port', 995)) alma_protokolu = request.form.get('alma_protokolu', 'imap').strip() e_posta = request.form.get('e_posta', '').strip() sifre = request.form.get('sifre', '').strip() kullanici_adi = request.form.get('kullanici_adi', '').strip() if not e_posta or not sifre: flash('E-posta ve şifre gereklidir.', 'danger') else: if ayarlar: db.execute("""UPDATE mail_ayarlar SET smtp_sunucu=?, smtp_port=?, imap_sunucu=?, imap_port=?, pop3_sunucu=?, pop3_port=?, alma_protokolu=?, e_posta=?, sifre=?, kullanici_adi=? WHERE firma_id=?""", (smtp_sunucu, smtp_port, imap_sunucu, imap_port, pop3_sunucu, pop3_port, alma_protokolu, e_posta, sifre, kullanici_adi, firma_id)) else: db.execute("""INSERT INTO mail_ayarlar (firma_id, smtp_sunucu, smtp_port, imap_sunucu, imap_port, pop3_sunucu, pop3_port, alma_protokolu, e_posta, sifre, kullanici_adi) VALUES (?,?,?,?,?,?,?,?,?,?,?)""", (firma_id, smtp_sunucu, smtp_port, imap_sunucu, imap_port, pop3_sunucu, pop3_port, alma_protokolu, e_posta, sifre, kullanici_adi)) db.commit() flash('Mail ayarları kaydedildi.', 'success') return redirect(url_for('firma_eposta_ayarlar')) return render_template('firma_admin/eposta_ayarlar.html', firma=firma, ayarlar=ayarlar) @app.route('/firma-admin/eposta/test-baglanti', methods=['POST']) def firma_eposta_test_baglanti(): if 'firma_id' not in session and 'uid' not in session: return jsonify({'success': False, 'message': 'Giriş yapmalısınız'}), 401 data = request.get_json() e_posta = data.get('e_posta', '') sifre = data.get('sifre', '') smtp_sunucu = data.get('smtp_sunucu', '') smtp_port = data.get('smtp_port', 465) if not e_posta or not sifre: return jsonify({'success': False, 'message': 'E-posta ve şifre gereklidir.'}) try: if smtp_port == 465: server = smtplib.SMTP_SSL(smtp_sunucu, smtp_port, timeout=10) else: server = smtplib.SMTP(smtp_sunucu, smtp_port, timeout=10) server.ehlo() server.starttls() server.ehlo() server.login(e_posta, sifre) server.quit() return jsonify({'success': True, 'message': f'Bağlantı başarılı! {smtp_sunucu}:{smtp_port}'}) except smtplib.SMTPAuthenticationError: return jsonify({'success': False, 'message': 'Kullanıcı adı veya şifre hatalı!'}) except smtplib.SMTPConnectError: return jsonify({'success': False, 'message': f'{smtp_sunucu} sunucusuna bağlanamadı!'}) except socket.timeout: return jsonify({'success': False, 'message': 'Bağlantı zaman aşımına uğradı!'}) except Exception as e: return jsonify({'success': False, 'message': f'Hata: {str(e)}'}) @app.route('/firma-admin/eposta/test') def firma_eposta_test(): if 'firma_id' not in session and 'uid' not in session: return redirect(url_for('login')) db = get_db() # Admin ise ilk firmaya yönlendir if 'uid' in session and 'firma_id' not in session: firma = db.execute("SELECT * FROM firmalar WHERE onay=1 ORDER BY id LIMIT 1").fetchone() if firma: session['firma_id'] = firma['id'] session['firma_adi'] = firma['firma_adi'] session['yetkili'] = firma['yetkili_adi'] session['firma_logo'] = firma['logo'] session['giris_turu'] = 'firma' else: flash('Henüz onaylı firma bulunmuyor.', 'warning') return redirect(url_for('firma_eposta')) firma_id = session['firma_id'] ayarlar = db.execute("SELECT * FROM mail_ayarlar WHERE firma_id=?", (firma_id,)).fetchone() if not ayarlar: flash('Önce mail ayarlarını yapın.', 'danger') return redirect(url_for('firma_eposta_ayarlar')) alici = ayarlar['e_posta'] konu = 'Kolay Takip - Test Maili' icerik = f"""Merhaba, Bu bir test mailidir. Mail ayarlarınız doğru çalışmaktadır. Gönderen: {ayarlar['e_posta']} SMTP Sunucu: {ayarlar['smtp_sunucu']}:{ayarlar['smtp_port']} IMAP Sunucu: {ayarlar['imap_sunucu']}:{ayarlar['imap_port']} Saygılarımızla, Kolay Takip Ekibi """ basarili, mesaj = mail_gonder(firma_id, alici, konu, icerik) if basarili: flash(f'Test maili başarıyla gönderildi! {alici} adresini kontrol edin.', 'success') else: flash(f'Test maili gönderilemedi: {mesaj}', 'danger') return redirect(url_for('firma_eposta_ayarlar')) if __name__ == '__main__': if not os.path.exists(DB): import subprocess subprocess.run(['sqlite3', DB, '.read schema.sql'], check=False) # fallback: elle oluştur conn = sqlite3.connect(DB) conn.executescript(open('schema.sql').read()) pw = generate_password_hash('admin123') conn.execute("INSERT OR IGNORE INTO kullanicilar (kullanici_adi, sifre, ad_soyad, email, rol_id) VALUES ('admin',?,'Sistem Yöneticisi','admin@test.com',1)", (pw,)) conn.commit() conn.close() app.run(debug=False, port=5003)