File size: 9,368 Bytes
c4e396b
948f4e4
fc0b5d3
a77f014
948f4e4
b8d9468
 
c4e396b
38c73fc
a77f014
 
 
948f4e4
 
c4e396b
948f4e4
 
 
 
 
 
 
 
332329c
b8d9468
c4e396b
332329c
fc0b5d3
 
89dbcd5
fc0b5d3
b8d9468
f7c7abf
 
948f4e4
a77f014
948f4e4
 
a77f014
 
 
c4e396b
 
948f4e4
c4e396b
fec02ce
b8d9468
948f4e4
 
 
b8d9468
faa4b34
b8d9468
 
948f4e4
b8d9468
 
faa4b34
b8d9468
 
faa4b34
b8d9468
faa4b34
b8d9468
 
 
 
 
 
 
 
 
faa4b34
948f4e4
f7c7abf
fc0b5d3
89dbcd5
948f4e4
c4e396b
fc0b5d3
c4e396b
fc0b5d3
f7c7abf
fc0b5d3
 
 
332329c
a497fa8
 
 
 
fc0b5d3
 
c4e396b
 
 
 
332329c
c4e396b
332329c
 
0816899
 
 
faa4b34
0816899
 
948f4e4
c4e396b
332329c
fc0b5d3
948f4e4
fec02ce
0816899
fec02ce
a990a67
b8d9468
 
a497fa8
0816899
 
a497fa8
 
 
b8d9468
0816899
 
b8d9468
 
0816899
a497fa8
 
0816899
 
c4e396b
fc0b5d3
948f4e4
fc0b5d3
332329c
a497fa8
 
 
c4e396b
faa4b34
a497fa8
0816899
 
 
d6f7d22
a497fa8
 
fec02ce
0816899
fec02ce
a990a67
a497fa8
0816899
 
a497fa8
b8d9468
fec02ce
a497fa8
0816899
c4e396b
a497fa8
fec02ce
b8d9468
a497fa8
b8d9468
 
 
 
0816899
 
c4e396b
a497fa8
 
 
 
332329c
 
89dbcd5
 
 
fc0b5d3
332329c
fc0b5d3
332329c
89dbcd5
 
948f4e4
fc0b5d3
332329c
 
948f4e4
89dbcd5
a990a67
c4e396b
fec02ce
 
fc0b5d3
 
a990a67
f7c7abf
fc0b5d3
 
 
fec02ce
fc0b5d3
 
 
89dbcd5
fc0b5d3
 
89dbcd5
faa4b34
9368f71
948f4e4
fc0b5d3
332329c
f7c7abf
fec02ce
948f4e4
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
from flask import Flask, request, jsonify, session, redirect, url_for, render_template, flash
from simple_salesforce import Salesforce, SalesforceAuthenticationFailed, SalesforceError
import os
from dotenv import load_dotenv
import logging
import bcrypt
from urllib.parse import quote
from datetime import timedelta

# Load environment variables
load_dotenv()

# Configure logging
logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('app.log'),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger(__name__)

app = Flask(__name__)
app.secret_key = os.getenv('FLASK_SECRET_KEY', 'tPhZ8oXGBoadFBQXgUkSR2kDH')
app.permanent_session_lifetime = timedelta(minutes=30)  # Session expires after 30 minutes

# Salesforce mock data for guest users
MOCK_DATA = {
    "supervisor_id": "GUEST",
    "project_id": "PROJ_001",
    "last_login": "Guest Mode"
}

def get_salesforce_connection():
    """Establish a Salesforce connection with detailed error handling."""
    try:
        sf = Salesforce(
            username=os.getenv('SALESFORCE_USERNAME'),
            password=os.getenv('SALESFORCE_PASSWORD'),
            security_token=os.getenv('SALESFORCE_SECURITY_TOKEN'),
            domain=os.getenv('SALESFORCE_DOMAIN', 'login'),
            version='60.0'
        )
        logger.info("Successfully connected to Salesforce")
        sf.query("SELECT Id FROM Supervisor__c LIMIT 1")
        logger.debug("Salesforce connection test query successful")
        return sf
    except SalesforceAuthenticationFailed as e:
        logger.error(f"Salesforce authentication failed: {str(e)}")
        raise Exception(f"Salesforce authentication failed: {str(e)}. Check your credentials.")
    except SalesforceError as e:
        logger.error(f"Salesforce error during connection: {str(e)}")
        raise Exception(f"Salesforce error: {str(e)}. Check object permissions and API access.")
    except Exception as e:
        logger.error(f"Unexpected error connecting to Salesforce: {str(e)}")
        raise Exception(f"Unable to connect to Salesforce: {str(e)}. Please check your configuration.")

def hash_password(password):
    """Hash a password using bcrypt."""
    try:
        return bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')
    except Exception as e:
        logger.error(f"Password hashing failed: {str(e)}")
        raise

def verify_password(password, hashed_password):
    """Verify a password against its hash."""
    try:
        return bcrypt.checkpw(password.encode('utf-8'), hashed_password.encode('utf-8'))
    except Exception as e:
        logger.error(f"Password verification failed: {str(e)}")
        return False

@app.route('/')
def index():
    if 'supervisor_id' not in session:
        logger.info("User not logged in, redirecting to login page")
        flash("Please log in to access the dashboard.", "warning")
        return redirect(url_for('login_page'))
    logger.info(f"Redirecting user {session['supervisor_id']} to index")
    return render_template('index.html')

@app.route('/login', methods=['GET'])
def login_page():
    return render_template('login.html')

@app.route('/signup', methods=['GET'])
def signup_page():
    return render_template('signup.html')

@app.route('/login', methods=['POST'])
def login():
    if 'supervisor_id' in session:
        logger.info(f"User {session['supervisor_id']} already logged in, redirecting to index")
        return jsonify({"status": "success", "message": "Already logged in", "redirect": "/"}), 200

    data = request.get_json()
    supervisor_id = data.get('supervisor_id')
    password = data.get('password')

    if not supervisor_id or not password:
        logger.warning("Login failed: Supervisor ID and password are required")
        return jsonify({"status": "error", "message": "Supervisor ID and password are required"}), 400

    if supervisor_id == 'GUEST':
        session['supervisor_id'] = 'GUEST'
        logger.info("Guest login successful")
        return jsonify({"status": "success", "message": "Logged in as guest", "redirect": "/"})

    try:
        sf = get_salesforce_connection()
        logger.debug(f"Querying Salesforce for Supervisor_ID__c: {supervisor_id}")
        supervisor_id_escaped = quote(supervisor_id, safe='')
        query = f"SELECT Id, Name, Password__c FROM Supervisor__c WHERE Name = '{supervisor_id_escaped}' LIMIT 1"
        result = sf.query(query)
        logger.debug(f"Salesforce query result: {result}")

        if not result['records']:
            logger.warning(f"Invalid Supervisor ID: {supervisor_id}")
            return jsonify({"status": "error", "message": "Invalid Supervisor ID"}), 401

        record = result['records'][0]
        stored_password = record['Password__c']
        if not stored_password:
            logger.warning(f"No password set for Supervisor ID: {supervisor_id}")
            return jsonify({"status": "error", "message": "No password set for this Supervisor ID"}), 401

        if not verify_password(password, stored_password):
            logger.warning(f"Invalid password for Supervisor ID: {supervisor_id}")
            return jsonify({"status": "error", "message": "Invalid password"}), 401

        session['supervisor_id'] = supervisor_id
        logger.info(f"Login successful for {supervisor_id}")
        return jsonify({"status": "success", "message": "Login successful", "redirect": "/"})
    except Exception as e:
        logger.error(f"Login error: {str(e)}")
        return jsonify({"status": "error", "message": str(e)}), 500

@app.route('/signup', methods=['POST'])
def signup():
    data = request.get_json()
    supervisor_id = data.get('supervisor_id')
    password = data.get('password')

    if not supervisor_id or not password:
        logger.warning("Signup failed: Supervisor ID and password are required")
        return jsonify({"status": "error", "message": "Supervisor ID and password are required"}), 400

    try:
        sf = get_salesforce_connection()
        logger.debug(f"Checking if Supervisor_ID__c {supervisor_id} already exists")
        supervisor_id_escaped = quote(supervisor_id, safe='')
        query = f"SELECT Id FROM Supervisor__c WHERE Name = '{supervisor_id_escaped}' LIMIT 1"
        result = sf.query(query)
        if result['records']:
            logger.warning(f"Signup failed: Supervisor ID {supervisor_id} already exists")
            return jsonify({"status": "error", "message": "Supervisor ID already exists"}), 400

        hashed_password = hash_password(password)
        logger.debug(f"Creating new Supervisor__c record for {supervisor_id}")
        new_record = {
            'Name': supervisor_id,
            'Password__c': hashed_password
        }
        response = sf.Supervisor__c.create(new_record)
        logger.debug(f"Salesforce create response: {response}")

        if not response.get('success'):
            logger.error(f"Failed to create Supervisor record: {response.get('errors')}")
            return jsonify({"status": "error", "message": f"Failed to create record in Salesforce: {response.get('errors')}"}), 500

        session['supervisor_id'] = supervisor_id
        logger.info(f"Signup successful for {supervisor_id}")
        return jsonify({"status": "success", "message": "Signup successful, you are now logged in", "redirect": "/"})
    except Exception as e:
        logger.error(f"Signup error: {str(e)}")
        return jsonify({"status": "error", "message": str(e)}), 500

@app.route('/logout', methods=['POST'])
def logout():
    supervisor_id = session.get('supervisor_id', 'Unknown')
    session.pop('supervisor_id', None)
    logger.info(f"User {supervisor_id} logged out")
    return jsonify({"status": "success", "message": "Logged out successfully"})

@app.route('/get_supervisor_data')
def get_supervisor_data():
    supervisor_id = session.get('supervisor_id', 'GUEST')
    if supervisor_id == 'GUEST':
        logger.info("Returning mock data for guest user")
        return jsonify({"status": "success", "data": MOCK_DATA})

    try:
        sf = get_salesforce_connection()
        supervisor_id_escaped = quote(supervisor_id, safe='')
        query = f"""
            SELECT Supervisor_ID__c, Project_ID__c
            FROM Supervisor__c
            WHERE Supervisor_ID__c = '{supervisor_id_escaped}'
            LIMIT 1
        """
        result = sf.query(query)

        if result['records']:
            record = result['records'][0]
            data = {
                "supervisor_id": record['Supervisor_ID__c'],
                "project_id": record['Project_ID__c'],
                "last_login": str(datetime.now())
            }
            logger.info(f"Fetched data for supervisor {supervisor_id}")
            return jsonify({"status": "success", "data": data})
        else:
            logger.warning(f"No data found for supervisor {supervisor_id}")
            return jsonify({"status": "error", "message": "No data found for this supervisor"}), 404
    except Exception as e:
        logger.error(f"Error fetching supervisor data: {str(e)}")
        return jsonify({"status": "error", "message": str(e)}), 500

if __name__ == '__main__':
    port = int(os.getenv('PORT', 5000))
    app.run(host='0.0.0.0', port=port, debug=True)