-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
1999 lines (1561 loc) · 78.6 KB
/
main.py
File metadata and controls
1999 lines (1561 loc) · 78.6 KB
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
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
import pymysql
import re
import requests
import hashlib
import time
import smtplib
import random
import string
import subprocess
import sys
import os
import pytz
import logging
import pymysql.cursors
from flask import Flask, render_template, request, redirect, url_for, flash, session, jsonify, send_from_directory, send_file
from flask_socketio import SocketIO
from flask_session import Session
from datetime import datetime, timedelta
from flask_cors import CORS
from flask_sslify import SSLify
from flask_bcrypt import Bcrypt
from decouple import config
from logging.handlers import RotatingFileHandler
from dotenv import load_dotenv
import base64
import json
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
app = Flask(__name__ )
app.config['SESSION_TYPE'] = 'filesystem'
Session(app)
app.permanent_session_lifetime = timedelta(minutes=2) # Sesinya berakhir dalam 2 menit tidak aktif
load_dotenv()
app.secret_key = os.getenv("SECRET_KEY")
app.config['DEBUG'] = True
ssl = SSLify(app)
socketio = SocketIO(app)
cors = CORS(app)
bcrypt = Bcrypt()
# Fungsi untuk memeriksa dan menginstal dependensi
def check_dependencies():
try:
import flask
except ImportError:
print("Flask belum terinstal. Menginstal Flask...")
subprocess.check_call([sys.executable, "-m", "pip", "install", "-r", "requirements.txt"])
else:
print("Semua kebutuhan sudah terinstal.")
# Panggil fungsi untuk memeriksa dependensi
check_dependencies()
# Membuat folder logs jika belum ada
if not os.path.exists('logs'):
os.makedirs('logs')
# Membuat folder logs/aktivitas_user jika belum ada
if not os.path.exists('logs/aktivitas_user'):
os.makedirs('logs/aktivitas_user')
# Inisialisasi logger
log_folder = 'logs/visit_ip'
if not os.path.exists(log_folder):
os.makedirs(log_folder)
log_file = os.path.join(log_folder, 'visit.log')
handler = RotatingFileHandler(log_file, maxBytes=100000, backupCount=1) # Maksimum 100KB per file, maksimum 1 backup file
handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s'))
logger = logging.getLogger(__name__)
logger.addHandler(handler)
logger.setLevel(logging.INFO)
# Koneksi ke database
conn = pymysql.connect(
host=config('DB_HOST'),
user=config('DB_USER'),
password=config('DB_PASSWORD'),
database=config('DB_NAME'),
cursorclass=pymysql.cursors.DictCursor
)
def get_db_connection():
connection = pymysql.connect(
host=config('DB_HOST'),
user=config('DB_USER'),
password=config('DB_PASSWORD'),
database=config('DB_NAME'),
cursorclass=pymysql.cursors.DictCursor
)
return connection
# Inisialisasi logger untuk log permintaan GET
get_logger = logging.getLogger('get_logger')
get_logger.setLevel(logging.INFO)
get_handler = logging.FileHandler('logs/get_logs/get_requests.log')
get_formatter = logging.Formatter('%(asctime)s - %(message)s')
get_handler.setFormatter(get_formatter)
get_logger.addHandler(get_handler)
# Inisialisasi logger untuk log aktivitas klaim point
claim_logger = logging.getLogger('claim_logger')
claim_logger.setLevel(logging.INFO)
claim_handler = logging.FileHandler('logs/aktivitas_user/claim_point.log')
claim_formatter = logging.Formatter('%(asctime)s - %(message)s')
claim_handler.setFormatter(claim_formatter)
claim_logger.addHandler(claim_handler)
# Inisialisasi logger untuk log aktivitas redeem point
redeem_logger = logging.getLogger('redeem_logger')
redeem_logger.setLevel(logging.INFO)
redeem_handler = logging.FileHandler('logs/aktivitas_user/redeem_point.log')
redeem_formatter = logging.Formatter('%(asctime)s - %(message)s')
redeem_handler.setFormatter(redeem_formatter)
redeem_logger.addHandler(redeem_handler)
# Fungsi untuk inisialisasi logger kunjungan
def init_visit_logger():
visit_logger = logging.getLogger('visit_logger')
visit_logger.setLevel(logging.INFO)
visit_handler = logging.FileHandler('logs/visit_ip/visit.log')
visit_formatter = logging.Formatter('%(asctime)s - IP: %(ip)s - %(message)s')
visit_handler.setFormatter(visit_formatter)
visit_logger.addHandler(visit_handler)
return visit_logger
# Konfigurasi logger untuk menyimpan log ke file
log_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
tele_log = logging.getLogger('tele_log')
tele_log.setLevel(logging.INFO)
log_file = 'logs/tele_log/log_tele.log'
file_handler = logging.FileHandler(log_file)
file_handler.setFormatter(log_formatter)
tele_log.addHandler(file_handler)
visit_logger = init_visit_logger()
# Struktur data untuk melacak kunjungan dari setiap IP
visit_count = {}
@app.route('/log-visit', methods=['POST'])
def log_visit():
data = request.get_json()
user_ip = data.get('ip')
visited_page = request.referrer # Mendapatkan URL halaman sebelumnya yang dikunjungi oleh pengguna
# Periksa apakah referrer ada dan tidak sama dengan halaman sebelumnya di session
if visited_page and visited_page != session.get('previous_page'):
# Format pesan log sesuai keinginan
log_message = 'User dengan IP {} mengunjungi halaman {}'.format(user_ip, visited_page)
# Catat log dengan format yang diinginkan
visit_logger.info(log_message, extra={'ip': user_ip})
# Simpan referrer sebagai halaman sebelumnya
session['previous_page'] = visited_page
# Periksa apakah IP sudah ada dalam daftar kunjungan
if user_ip in visit_count:
visit_count[user_ip] += 1
else:
visit_count[user_ip] = 1
return 'Visit logged successfully'
@app.route('/get-visit-count')
def get_visit_count():
# Kirim data kunjungan ke halaman admin
return jsonify(visit_count)
# Fungsi untuk menangani kesalahan 404
@app.errorhandler(404)
def not_found(error):
print(f"Error occurred: {error}") # Menggunakan variabel error untuk mencetak informasi kesalahan
return send_from_directory('static/404', '404.html'), 404
# Ini web pertama kali dimuat
@app.route('/')
def serve_index():
# Menyimpan informasi permintaan GET ke file log
log_message = f"Received GET request from {request.remote_addr} for {request.url}"
get_logger.info(log_message)
# Periksa apakah pengguna sudah login (gunakan session/cookie)
if 'username' in session:
# Jika pengguna sudah login, arahkan ke halaman dashboard
return redirect(url_for('dashboard'))
else:
# Jika pengguna belum login, kirimkan file index.html dari folder 'home'
return send_file('home/index.html') # Mengirimkan file index.html
# Ini kalo permintaan /index.html akan kembali ke /
@app.route('/index.html')
def redirect_to_index():
# Menyimpan informasi permintaan GET ke file log
log_message = f"Received GET request from {request.remote_addr} for {request.url}"
get_logger.info(log_message)
return redirect(url_for('serve_index'))
# Fungsi untuk rute /about.html
@app.route('/about')
def serve_about():
# Menyimpan informasi permintaan GET ke file log
log_message = f"Received GET request from {request.remote_addr} for {request.url}"
get_logger.info(log_message)
if 'username' in session:
return redirect(url_for('serve_index'))
else:
return send_file('home/about.html') # Mengirimkan file login.html dari folder 'login'
# Fungsi untuk rute /privacy.html
@app.route('/privacy.html')
def serve_privacy():
# Menyimpan informasi permintaan GET ke file log
log_message = f"Received GET request from {request.remote_addr} for {request.url}"
get_logger.info(log_message)
if 'username' in session:
return redirect(url_for('serve_index'))
else:
return send_file('home/privacy.html') # Mengirimkan file privacy.html dari folder 'home'
# Fungsi untuk rute /dashboard.html
@app.route('/dashboard.html')
def serve_dashboard():
# Menyimpan informasi permintaan GET ke file log
log_message = f"Received GET request from {request.remote_addr} for {request.url}"
get_logger.info(log_message)
if 'username' in session:
return render_template('main/dashboard.html')
else:
return redirect(url_for('serve_index'))
# Fungsi untuk rute /login.html
@app.route('/login.html')
def serve_login():
# Menyimpan informasi permintaan GET ke file log
log_message = f"Received GET request from {request.remote_addr} for {request.url}"
get_logger.info(log_message)
return render_template('login/login.html')
# Fungsi untuk rute /signup.html
@app.route('/signup.html')
def serve_signup():
# Menyimpan informasi permintaan GET ke file log
log_message = f"Received GET request from {request.remote_addr} for {request.url}"
get_logger.info(log_message)
return render_template('signup/signup.html')
# Fungsi untuk rute /redeem.html
@app.route('/redeem.html')
def serve_redeem():
# Menyimpan informasi permintaan GET ke file log
log_message = f"Received GET request from {request.remote_addr} for {request.url}"
get_logger.info(log_message)
if 'username' in session:
return render_template('main/redeem.html')
else:
return render_template('login/login.html')
# Fungsi untuk rute /claim_point.html
@app.route('/claim_point.html')
def serve_claim_point():
# Menyimpan informasi permintaan GET ke file log
log_message = f"Received GET request from {request.remote_addr} for {request.url}"
get_logger.info(log_message)
if 'username' in session:
return render_template('main/claim_point.html')
else:
return render_template('login/login.html')
# Fungsi untuk rute /logout.html
@app.route('/logout.html')
def serve_logout():
# Menyimpan informasi permintaan GET ke file log
log_message = f"Received GET request from {request.remote_addr} for {request.url}"
get_logger.info(log_message)
# Hapus session/cookie untuk menandakan pengguna sudah logout
session.pop('username', None)
# Arahkan pengguna kembali ke halaman utama
return redirect(url_for('serve_index'))
# Fungsi untuk rute /forgot_password.html
@app.route('/forgot_password.html')
def serve_forgot_password():
# Menyimpan informasi permintaan GET ke file log
log_message = f"Received GET request from {request.remote_addr} for {request.url}"
get_logger.info(log_message)
return render_template('login/forgot_password.html')
# Tentukan direktori tempat file statis disimpan
static_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'static')
# Fungsi untuk rute /forgot_password.html
@app.route('/forgot_username.html')
def serve_forgot_username():
# Menyimpan informasi permintaan GET ke file log
log_message = f"Received GET request from {request.remote_addr} for {request.url}"
get_logger.info(log_message)
return render_template('login/forgot_username.html')
# Tentukan direktori tempat file statis disimpan
static_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'static')
# Route untuk file gambar di images/
@app.route('/static/images/<filename>')
def serve_images(filename):
# Menyimpan informasi permintaan GET ke file log
log_message = f"Received GET request from {request.remote_addr} for {request.url}"
get_logger.info(log_message)
file_path = os.path.join(static_dir, 'images', filename)
if os.path.isfile(file_path):
return send_from_directory(os.path.join(static_dir, 'images'), filename)
else:
return "File not found", 404
# Rute untuk menangani permintaan favicon.ico
@app.route('/favicon.ico')
def favicon():
# Menyimpan informasi permintaan GET ke file log
log_message = f"Received GET request from {request.remote_addr} for {request.url}"
get_logger.info(log_message)
# Mengirimkan favicon.ico dari direktori "images" di dalam direktori "static"
return send_from_directory(os.path.join(static_dir, 'images/favicon'), 'ireload.ico', mimetype='image/vnd.microsoft.icon')
@app.route('/signup', methods=['GET', 'POST'])
def signup():
# Menyimpan informasi permintaan GET ke file log
log_message = f"Received GET request from {request.remote_addr} for {request.url}"
get_logger.info(log_message)
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
if not request.form.get('agree_tnc'):
flash('Harap setujui T&C sebelum melanjutkan.')
return redirect(url_for('signup'))
is_valid_username_result, username_message = is_valid_username(username)
is_valid_password_result, password_message = is_valid_password(password)
if not_a_valid_username(username):
flash('Username tidak valid. Pastikan username dimulai dengan huruf besar dan hanya mengandung huruf besar, huruf kecil, dan angka.')
if not is_valid_username_result:
flash(username_message)
elif not is_valid_password_result:
flash(password_message)
else:
# Dapatkan koneksi dan objek cursor
connection = get_db_connection()
cursor = connection.cursor()
cursor.execute("SELECT * FROM users WHERE username=%s", (username,))
existing_user = cursor.fetchone()
if existing_user:
flash(f'Username {username} sudah ada. Silakan pilih username lain.')
else:
# Validasi password
if not is_valid_password(password):
flash('Password harus memiliki panjang antara 5 dan 11 karakter.')
else:
hashed_password = bcrypt.generate_password_hash(password).decode('utf-8')
cursor.execute("INSERT INTO users (username, password, points) VALUES (%s, %s, %s)", (username, hashed_password, 500))
connection.commit()
user_id = cursor.lastrowid
points_earned = 500
transaction_type = 'Bonus Sign Up +'
cursor.execute("INSERT INTO point_history (user_id, points_change, transaction_type) VALUES (%s, %s, %s)", (user_id, points_earned, transaction_type))
connection.commit()
flash(f'Silahkan login menggunakan username Anda: {username} & password Anda.')
# Tutup kursor dan koneksi saat selesai
cursor.close()
connection.close()
return redirect(url_for('signup'))
return render_template('signup/signup.html')
def is_valid_password(password):
# Validasi panjang minimal 5 dan maksimal 11 karakter
if not (5 <= len(password) <= 20):
return False, "Password harus memiliki panjang antara 5 dan 11 karakter. Contoh :ReloadCell123@!@"
# Validasi huruf besar
if not any(char.isupper() for char in password):
return False, "Password harus mengandung setidaknya satu huruf besar. Contoh :ReloadCell123@!@"
# Validasi huruf kecil
if not any(char.islower() for char in password):
return False, "Password harus mengandung setidaknya satu huruf kecil. Contoh :ReloadCell123@!@"
# Validasi angka
if not any(char.isdigit() for char in password):
return False, "Password harus mengandung setidaknya satu angka. Contoh :ReloadCell123@!@"
# Validasi karakter khusus
special_characters = "!@#$%^&*()_+={}|:;'<>,.?/"
if not any(char in special_characters for char in password):
return False, "Password harus mengandung setidaknya satu karakter khusus. Contoh :ReloadCell123@!@ "
# Password valid
return True, "Password valid."
def is_valid_username(username):
# Ekspresi reguler untuk memeriksa validitas username
pattern = r"^[a-zA-Z0-9_-]{5,20}$"
# Validasi username tidak boleh mengandung spasi
if " " in username:
return False, "Username tidak boleh mengandung spasi. Contoh : ReloadCell0910"
# Validasi username tidak boleh mengandung karakter yang tidak dapat ditampilkan
if not username.isprintable():
return False, "Username harus hanya mengandung karakter yang dapat ditampilkan. Contoh : ReloadCell0910"
# Validasi username tidak boleh mengandung karakter yang dapat digunakan untuk serangan SQL injection
if re.search(r"[;'`]", username):
return False, "Username tidak boleh mengandung karakter khusus seperti ';`. Contoh : ReloadCell0910"
# Validasi menggunakan ekspresi reguler
if not re.match(pattern, username):
return False, "Username harus terdiri dari 5-20 karakter, hanya huruf besar, huruf kecil, angka, '_', dan '-'. Contoh : ReloadCell0910"
# Username valid, cetak ke konsol aplikasi
return True, "Username valid."
def not_a_valid_username(username):
is_valid, message = is_valid_username(username)
if not is_valid:
print(f"Input username: {username} Tidak Valid. Alasan: {message}")
return not is_valid
# Fungsi untuk mengirim email konfirmasi login
def send_login_confirmation_email(username, email):
subject = 'Login Confirmation'
template_path = 'templates/login_confirmation/login_confirmation.html'
# Mendapatkan alamat IP pengunjung
ip_address = request.remote_addr
# Mendapatkan informasi lokasi berdasarkan alamat IP
location_info = get_location_info(ip_address)
# Membaca template HTML
with open(template_path, 'r') as file:
html_template = file.read()
# Mengganti placeholders dalam template dengan nilai yang sesuai
html_template = html_template.replace('{{ username }}', username)
html_template = html_template.replace('{{ ip_address }}', location_info)
# Membuat pesan email
msg = MIMEMultipart()
msg['From'] = os.getenv('SENDER_EMAIL')
msg['To'] = email
msg['Subject'] = subject
# Melampirkan versi HTML dari email
msg.attach(MIMEText(html_template, 'html'))
# Membaca gambar/logo dan melampirkannya
with open('templates/lupa_username/logo_1.png', 'rb') as image_file:
logo_image = MIMEImage(image_file.read())
logo_image.add_header('Content-ID', '<logo>')
msg.attach(logo_image)
# Mengirim email melalui SMTP server
server = smtplib.SMTP(os.getenv('SMTP_SERVER'), int(os.getenv('SMTP_PORT')))
server.starttls()
server.login(os.getenv('SENDER_EMAIL'), os.getenv('SENDER_PASSWORD'))
server.sendmail(os.getenv('SENDER_EMAIL'), email, msg.as_string())
server.quit()
# Fungsi untuk mendapatkan alamat email pengguna berdasarkan user_id
def get_user_email(user_id):
cursor = conn.cursor()
cursor.execute("SELECT email FROM users_profile WHERE user_id=%s", (user_id,))
result = cursor.fetchone()
return result['email'] if result else None
#login users
@app.route('/login', methods=['GET', 'POST'])
def login():
log_message = f"Received GET request from {request.remote_addr} for {request.url}"
get_logger.info(log_message)
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
cursor = conn.cursor()
cursor.execute("SELECT * FROM users WHERE username=%s", (username,))
user = cursor.fetchone()
if user:
if user['status'] == 'active':
hashed_password = user['password'] # Ambil kata sandi yang telah di-hash dari database
if bcrypt.check_password_hash(hashed_password, password):
session['username'] = user['username']
session['loggedin'] = True # Tandai pengguna telah login
# Kirim email konfirmasi login
email = get_user_email(user['id'])
send_login_confirmation_email(username, email)
# Catat alamat IP, lokasi, dan waktu login
ip_address = request.remote_addr
location_info = get_location_info(ip_address)
login_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
log_message = f"User '{username}' logged in from IP: {ip_address}, Location: {location_info}, Time: {login_time}"
# Tampilkan pesan Login Berhasil anda akan diarahkan ke halaman dashboard dalam hitungan mundur dari 5 dengan dinamis
flash('Login Berhasil! Anda akan diarahkan ke halaman dashboard dalam hitungan mundur dari 5 detik.', 'success')
# Redirect ke halaman login untuk menampilkan pesan login berhasil dengan hitungan mundur
return redirect(url_for('login'))
else:
error_message = 'Username atau password salah. Periksa kembali username dan password Anda.'
else:
error_message = 'Akun Anda tidak aktif. Hubungi administrator.'
else:
error_message = 'Username atau password salah. Periksa kembali username dan password Anda.'
flash(error_message, 'error') # Gunakan flash untuk menyimpan pesan kesalahan
return render_template('login/login.html')
return render_template('login/login.html')
# Fungsi untuk mendapatkan informasi lokasi berdasarkan alamat IP
def get_location_info(ip_address):
try:
response = requests.get(f'http://ip-api.com/json/{ip_address}', timeout=5) # Timeout set to 5 seconds
if response.status_code == 200:
data = response.json()
if data['status'] == 'success':
location_info = f"{data['city']}, {data['regionName']}, {data['country']}"
return location_info
else:
return 'Unknown'
else:
return 'Unknown'
except Exception as e:
return 'Unknown'
# Fungsi untuk generate reset token
def generate_reset_token(length=8):
characters = string.ascii_letters + string.digits
reset_token = ''.join(random.choice(characters) for i in range(length))
return reset_token
reset_tokens = {} # Dictionary to store reset tokens and their expiration time
# Fungsi untuk send token dengan template HTML, logo, dan link
@app.route('/send-token', methods=['POST'])
def send_token():
data = request.get_json()
email = data.get('email')
if email:
# Memeriksa apakah pengguna sudah memiliki token reset yang aktif
if email in reset_tokens and reset_tokens[email]['expiration_time'] > datetime.now():
return jsonify(success=False, message='Anda sudah memiliki permintaan reset password yang aktif. Cek email Anda untuk petunjuk lebih lanjut.')
# Mendapatkan koneksi ke database
connection = get_db_connection()
try:
with connection.cursor() as cursor:
# Cari email dalam tabel users_profile
sql = "SELECT email, full_name FROM users_profile WHERE email = %s"
cursor.execute(sql, (email,))
user = cursor.fetchone()
if user:
reset_token = generate_reset_token()
reset_tokens[email] = {
'token': reset_token,
'expiration_time': datetime.now() + timedelta(minutes=1) # Token kedaluwarsa dalam 1 jam
}
# URL untuk mereset password
expires = int((datetime.now() + timedelta(minutes=1)).timestamp())
reset_link = f'http://localhost:5000/forgot_password.html?token={reset_token}&email={email}&expires={expires}'
# Kirim reset token ke email pengguna dengan template HTML, logo, dan link
subject = f'Berikut Kode Verifikasi Anda : {reset_token}'
template_path = 'templates/lupa_password/reset_token.html'
logo_path = 'templates/lupa_username/logo_1.png' # Path file logo
replacements = {
'full_name': user['full_name'],
'reset_token': reset_token,
'reset_link': reset_link
}
if send_email_token_with_template_and_logo_and_link(subject, email, template_path, replacements, logo_path, reset_link):
return jsonify(success=True, message='Email dengan petunjuk pengaturan ulang password telah dikirim.')
else:
return jsonify(success=False, message='Terjadi kesalahan saat mengirim email. Silakan coba lagi nanti.')
else:
return jsonify(success=False, message='Email tidak ditemukan. Pastikan Anda memasukkan email yang benar.')
except Exception as e:
print(f"Error: {e}")
return jsonify(success=False, message='Terjadi kesalahan saat mengirim email. Silakan coba lagi nanti.')
finally:
# Tutup koneksi setelah penggunaan
connection.close()
return jsonify(success=False, message='Terjadi kesalahan. Pastikan email valid.')
# Fungsi untuk mendapatkan full_name berdasarkan email dari basis data
def get_full_name_by_email(email):
connection = get_db_connection()
try:
with connection.cursor() as cursor:
sql_get_full_name = "SELECT full_name FROM users_profile WHERE email = %s"
cursor.execute(sql_get_full_name, (email,))
result = cursor.fetchone()
if result:
return result['full_name']
else:
return None
except Exception as e:
print(f"Error: {e}")
return None
finally:
# Tutup koneksi setelah penggunaan
connection.close()
# Fungsi untuk reset password
@app.route('/reset-password', methods=['POST'])
def reset_password():
data = request.get_json()
email = data.get('email')
token = data.get('token')
new_password = data.get('new_password')
if email and token and new_password:
# Periksa apakah token cocok dengan yang ada dalam dictionary reset_tokens
if email in reset_tokens and reset_tokens[email]['token'] == token:
# Periksa apakah token masih berlaku
if reset_tokens[email]['expiration_time'] > datetime.now():
# Hash password baru
hashed_password = bcrypt.generate_password_hash(new_password).decode('utf-8')
# Dapatkan user_id berdasarkan email dari tabel users_profile
connection = get_db_connection()
try:
with connection.cursor() as cursor:
sql_get_user_id = "SELECT user_id FROM users_profile WHERE email = %s"
cursor.execute(sql_get_user_id, (email,))
user_id = cursor.fetchone()
# Update password pengguna dengan password yang dihash
if user_id:
sql_update_password = "UPDATE users SET password = %s WHERE id = %s"
cursor.execute(sql_update_password, (hashed_password, user_id['user_id']))
connection.commit()
del reset_tokens[email] # Hapus token yang sudah digunakan
# Panggil fungsi untuk mengirim email konfirmasi
full_name = get_full_name_by_email(email)
if full_name:
send_password_changed_email(email, full_name)
else:
return jsonify(success=False, message='Eror.')
return jsonify(success=True, message='Selamat {{username}} Password Anda berhasil direset.')
else:
return jsonify(success=False, message='Email tidak valid.')
except Exception as e:
print(f"Error: {e}")
return jsonify(success=False, message='Terjadi kesalahan saat mereset password. Silakan coba lagi nanti.')
finally:
# Tutup koneksi setelah penggunaan
connection.close()
else:
return jsonify(success=False, message='Kode telah kedaluwarsa. Silakan minta Kode reset ulang.')
else:
return jsonify(success=False, message='Kode tidak valid. Silakan periksa kembali atau minta Kode reset ulang.')
else:
return jsonify(success=False, message='Permintaan tidak valid. Pastikan semua data terisi dengan benar.')
# Endpoint untuk forgot-username
@app.route('/forgot-username', methods=['POST'])
def forgot_username():
try:
# Ambil data email dari request
data = request.get_json()
email = data['email']
# Query database untuk mendapatkan username berdasarkan email dari tabel users_profile
connection = get_db_connection()
with connection.cursor() as cursor:
sql = "SELECT user_id, full_name FROM users_profile WHERE email = %s"
cursor.execute(sql, email)
result = cursor.fetchone()
if result:
user_id = result['user_id']
full_name = result['full_name']
# Cari username berdasarkan user_id di tabel users
with connection.cursor() as cursor:
sql = "SELECT username FROM users WHERE id = %s"
cursor.execute(sql, user_id)
username_result = cursor.fetchone()
if username_result:
username = username_result['username']
# Kirim email username ke alamat email pengguna
send_username_email(email, username, full_name)
# Respon sukses
response = {'message': 'Email berhasil dikirim,Silakan cek pada folder spam /inbox'}
return jsonify(response), 200
else:
# Respon jika username tidak ditemukan
response = {'error': 'Username tidak ditemukan,Kamu belum mendaftar'}
return jsonify(response), 404
else:
# Respon jika email tidak ditemukan di tabel users_profile
response = {'error': 'Email tidak terdaftar,Kamu belum mengedit profil'}
return jsonify(response), 404
except Exception as e:
# Respon jika terjadi error
response = {'error': f'Gagal mengirim email : {str(e)}'}
return jsonify(response), 500
# Fungsi untuk send email dengan template HTML, logo, dan link
def send_email_token_with_template_and_logo_and_link(subject, to_email, template_path, replacements, logo_path, reset_link):
try:
# Pengaturan informasi email pengirim dari file .env
sender_email = os.getenv('SENDER_EMAIL')
sender_password = os.getenv('SENDER_PASSWORD')
smtp_server = os.getenv('SMTP_SERVER') # Alamat SMTP server
smtp_port = int(os.getenv('SMTP_PORT')) # Port SMTP server
# Membaca template HTML dari file
with open(template_path, 'r') as template_file:
template_content = template_file.read()
# Mengganti placeholder dalam template dengan nilai yang sesuai
for key, value in replacements.items():
template_content = template_content.replace(f'{{{{ {key} }}}}', value)
# Membuat pesan email dengan template HTML, menyisipkan logo, dan menyertakan link
msg = MIMEMultipart('related')
msg['From'] = f'I Reload Cell <{sender_email}>' # Tambahkan Display Name di sini
msg['To'] = to_email
msg['Subject'] = subject
# Menyisipkan versi HTML dari pesan email dengan link
template_content_with_link = template_content.replace('{{ reset_link }}', reset_link)
msg.attach(MIMEText(template_content_with_link, 'html'))
# Menyisipkan logo sebagai gambar dalam pesan email
with open(logo_path, 'rb') as image_file:
logo_image = MIMEImage(image_file.read())
logo_image.add_header('Content-ID', '<logo>')
msg.attach(logo_image)
# Mengirim email melalui SMTP server
server = smtplib.SMTP(smtp_server, smtp_port)
server.starttls() # Menggunakan TLS (Transport Layer Security) untuk keamanan
server.login(sender_email, sender_password)
server.sendmail(sender_email, to_email, msg.as_string())
server.quit()
return True
except Exception as e:
print(f"Email gagal dikirim: {e}")
return False
# Fungsi untuk kirim email dengan template HTML dan teks
def send_username_email(email, username, full_name):
# Set sender email information from environment variables
sender_email = os.getenv('SENDER_EMAIL')
sender_password = os.getenv('SENDER_PASSWORD')
smtp_server = os.getenv('SMTP_SERVER')
smtp_port = int(os.getenv('SMTP_PORT'))
# Load HTML and text templates from the 'templates' folder
with open('templates/lupa_username/content.html', 'r') as html_file:
html_template = html_file.read()
with open('templates/lupa_username/content.txt', 'r') as text_file:
text_template = text_file.read()
# Replace placeholders in templates with actual data
html_body = html_template.replace('{{ full_name }}', full_name).replace('{{ username }}', username)
text_body = text_template.replace('{{ full_name }}', full_name).replace('{{ username }}', username)
try:
# Create email message
msg = MIMEMultipart('alternative')
msg['From'] = f'I Reload Cell <{sender_email}>' # Tambahkan Display Name di sini
msg['To'] = email
msg['Subject'] = ' Info Penting ! : Username Kamu Telah Ditemukan Nih! Cekidot! '
# Attach HTML version of the email
msg.attach(MIMEText(text_body, 'plain'))
msg.attach(MIMEText(html_body, 'html'))
# Attach logo image
with open('templates/lupa_username/logo_1.png', 'rb') as image_file:
logo_image = MIMEImage(image_file.read())
logo_image.add_header('Content-ID', '<logo>')
msg.attach(logo_image)
# Send the email via the SMTP server
server = smtplib.SMTP(smtp_server, smtp_port)
server.starttls()
server.login(sender_email, sender_password)
server.sendmail(sender_email, email, msg.as_string())
server.quit()
print("Email berhasil dikirim")
return True
except Exception as e:
print(f"Email gagal dikirim: {e}")
return False
# Fungsi untuk mengirim email konfirmasi reset password
def send_password_changed_email(email, full_name):
subject = 'Your Password Change Completed'
template_path = 'templates/password_changed/password_changed.html'
replacements = {
'full_name': full_name
}
return send_email_with_template(subject, email, template_path, replacements)
# Fungsi untuk mengirim email menggunakan template HTML
def send_email_with_template(subject, to_email, template_path, replacements):
try:
# Pengaturan informasi email pengirim dari file .env
sender_email = os.getenv('SENDER_EMAIL')
sender_password = os.getenv('SENDER_PASSWORD')
smtp_server = os.getenv('SMTP_SERVER')
smtp_port = int(os.getenv('SMTP_PORT'))
# Membaca template HTML
with open(template_path, 'r') as file:
html_template = file.read()
# Mengganti placeholders dalam template dengan nilai yang sesuai
for key, value in replacements.items():
html_template = html_template.replace('{{ ' + key + ' }}', value)
# Membuat pesan email
msg = MIMEMultipart()
msg['From'] = f'I Reload Cell <{sender_email}>' # Tambahkan Display Name di sini
msg['To'] = to_email
msg['Subject'] = subject
# Melampirkan versi HTML dari email
msg.attach(MIMEText(html_template, 'html'))
# Membaca gambar/logo
with open('templates/lupa_username/logo_1.png', 'rb') as image_file:
logo_image = MIMEImage(image_file.read())
logo_image.add_header('Content-ID', '<logo>')
msg.attach(logo_image)
# Mengirim email melalui SMTP server
server = smtplib.SMTP(smtp_server, smtp_port)
server.starttls()
server.login(sender_email, sender_password)
server.sendmail(sender_email, to_email, msg.as_string())
server.quit()
return True
except Exception as e:
print(f"Email gagal dikirim: {e}")
return False
# Endpoint untuk mengirim email konfirmasi setelah password diubah
@app.route('/send-password-changed-email', methods=['POST'])
def send_password_changed_email_endpoint():
data = request.get_json()
email = data.get('email')
full_name = data.get('full_name')
if email and full_name:
success = send_password_changed_email(email, full_name)
if success:
return jsonify(success=True, message='Email konfirmasi perubahan password berhasil dikirim.')
else:
return jsonify(success=False, message='Terjadi kesalahan saat mengirim email konfirmasi perubahan password.')
else:
return jsonify(success=False, message='Permintaan tidak valid. Pastikan semua data terisi dengan benar.')
@app.route('/dashboard')
def dashboard():
# Menyimpan informasi permintaan GET ke file log
log_message = f"Received GET request from {request.remote_addr} for {request.url}"
get_logger.info(log_message)
# Dapatkan koneksi dan objek cursor
connection = get_db_connection()
cursor = connection.cursor()
if 'loggedin' not in session:
# Jika 'loggedin' tidak ada dalam session, arahkan pengguna ke halaman login
return redirect(url_for('login'))
username = session['username']
userHasEditedProfile = session.get('userHasEditedProfile', False)
# Dapatkan waktu lokal Pekalongan
local_time = get_local_time()
# Tentukan sapaan berdasarkan waktu
current_hour = local_time.hour
greeting = "Selamat Malam"
if 5 <= current_hour < 12:
greeting = "Selamat Pagi"
elif 12 <= current_hour < 18:
greeting = "Selamat Siang"
elif 18 <= current_hour < 24 or 0 <= current_hour < 5:
greeting = "Selamat Sore/Malam"
cursor.execute("SELECT * FROM users WHERE username=%s", (username,))
user_data_from_db = cursor.fetchone()
if user_data_from_db:
user = {
'id': user_data_from_db['id'],
'username': user_data_from_db['username'],
'password': user_data_from_db['password'],
'points': user_data_from_db['points'],
'tanggal_mendapatkan_point': user_data_from_db['tanggal_mendapatkan_point'],
'tanggal_registrasi_user': user_data_from_db['tanggal_registrasi_user'],
'timezone': user_data_from_db['timezone']
}
# Konversi poin ke IDR dan format sebagai string sesuai format 'RpXXX.XXX'
points_in_idr = "Rp{:,.0f}".format(user['points']).replace(',', '.')
cursor.execute("SELECT * FROM point_history WHERE user_id=%s ORDER BY transaction_date DESC", (user['id'],))