Ajit Panday commited on
Commit
73e6ba6
·
1 Parent(s): 260918e

Update admin interface and add database credentials

Browse files
Files changed (3) hide show
  1. app/auth.py +21 -2
  2. app/models.py +120 -20
  3. app/static/admin.html +67 -45
app/auth.py CHANGED
@@ -111,9 +111,27 @@ async def create_customer(
111
  name=customer_data["name"],
112
  company_name=customer_data["company_name"],
113
  email=customer_data["email"],
114
- api_key=str(secrets.token_urlsafe(32))
 
 
 
 
115
  )
116
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  db.add(customer)
118
  db.commit()
119
  db.refresh(customer)
@@ -123,7 +141,8 @@ async def create_customer(
123
  "name": customer.name,
124
  "company_name": customer.company_name,
125
  "email": customer.email,
126
- "api_key": customer.api_key
 
127
  }
128
 
129
  @router.get("/customers/", response_model=List[CustomerSchema])
 
111
  name=customer_data["name"],
112
  company_name=customer_data["company_name"],
113
  email=customer_data["email"],
114
+ api_key=str(secrets.token_urlsafe(32)),
115
+ db_host=customer_data["db_host"],
116
+ db_user=customer_data["db_user"],
117
+ db_password=customer_data["db_password"],
118
+ db_name=customer_data["db_name"]
119
  )
120
 
121
+ # Test database connection
122
+ if not customer.get_db_engine():
123
+ raise HTTPException(
124
+ status_code=status.HTTP_400_BAD_REQUEST,
125
+ detail="Invalid database credentials or connection failed"
126
+ )
127
+
128
+ # Create tables in customer's database
129
+ if not customer.create_tables():
130
+ raise HTTPException(
131
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
132
+ detail="Failed to create database tables"
133
+ )
134
+
135
  db.add(customer)
136
  db.commit()
137
  db.refresh(customer)
 
141
  "name": customer.name,
142
  "company_name": customer.company_name,
143
  "email": customer.email,
144
+ "api_key": customer.api_key,
145
+ "is_active": customer.is_active
146
  }
147
 
148
  @router.get("/customers/", response_model=List[CustomerSchema])
app/models.py CHANGED
@@ -1,11 +1,12 @@
1
  from sqlalchemy import Column, Integer, String, DateTime, ForeignKey, Boolean, create_engine, Text
2
  from sqlalchemy.ext.declarative import declarative_base
3
- from sqlalchemy.orm import relationship
4
  from datetime import datetime
5
  import requests
6
  from typing import Optional, List, Dict
7
  from .settings import API_BASE_URL
8
  from .database import get_db
 
9
 
10
  # Create declarative base
11
  Base = declarative_base()
@@ -14,23 +15,123 @@ class Customer(Base):
14
  __tablename__ = "customers"
15
 
16
  id = Column(Integer, primary_key=True, index=True)
17
- name = Column(String(100), nullable=False)
18
- company_name = Column(String(100), nullable=False)
19
- email = Column(String(100), unique=True, nullable=False)
20
- api_key = Column(String(64), unique=True, nullable=False)
21
  is_active = Column(Boolean, default=True)
22
  created_at = Column(DateTime, default=datetime.utcnow)
23
  updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
24
- # Database credentials for customer's own database
25
- db_host = Column(String(255))
26
- db_port = Column(Integer)
27
- db_name = Column(String(100))
28
- db_user = Column(String(100))
29
- db_password = Column(String(255))
30
 
31
  # Relationship with call records
32
  call_records = relationship("CallRecord", back_populates="customer")
33
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  def get_db_url(self) -> Optional[str]:
35
  """Get database URL if credentials are configured"""
36
  if all([self.db_host, self.db_port, self.db_name, self.db_user, self.db_password]):
@@ -91,15 +192,14 @@ class Customer(Base):
91
  class CallRecord(Base):
92
  __tablename__ = "call_records"
93
 
94
- id = Column(String(36), primary_key=True)
95
- customer_id = Column(Integer, ForeignKey("customers.id"))
96
- caller_number = Column(String(20), nullable=False)
97
- called_number = Column(String(20), nullable=False)
98
- file_path = Column(String(255))
99
- transcription = Column(Text)
100
- summary = Column(Text)
101
- sentiment = Column(String(20))
102
- keywords = Column(Text)
103
  created_at = Column(DateTime, default=datetime.utcnow)
104
  updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
105
 
 
1
  from sqlalchemy import Column, Integer, String, DateTime, ForeignKey, Boolean, create_engine, Text
2
  from sqlalchemy.ext.declarative import declarative_base
3
+ from sqlalchemy.orm import relationship, sessionmaker
4
  from datetime import datetime
5
  import requests
6
  from typing import Optional, List, Dict
7
  from .settings import API_BASE_URL
8
  from .database import get_db
9
+ import os
10
 
11
  # Create declarative base
12
  Base = declarative_base()
 
15
  __tablename__ = "customers"
16
 
17
  id = Column(Integer, primary_key=True, index=True)
18
+ name = Column(String(255), nullable=False)
19
+ company_name = Column(String(255), nullable=False)
20
+ email = Column(String(255), unique=True, nullable=False)
21
+ api_key = Column(String(255), unique=True, nullable=False)
22
  is_active = Column(Boolean, default=True)
23
  created_at = Column(DateTime, default=datetime.utcnow)
24
  updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
25
+
26
+ # Database credentials
27
+ db_host = Column(String(255), nullable=False)
28
+ db_user = Column(String(255), nullable=False)
29
+ db_password = Column(String(255), nullable=False)
30
+ db_name = Column(String(255), nullable=False)
31
 
32
  # Relationship with call records
33
  call_records = relationship("CallRecord", back_populates="customer")
34
 
35
+ def get_db_engine(self):
36
+ """Get SQLAlchemy engine for customer's database"""
37
+ try:
38
+ # Construct database URL
39
+ db_url = f"mysql+pymysql://{self.db_user}:{self.db_password}@{self.db_host}/{self.db_name}"
40
+
41
+ # Create engine
42
+ engine = create_engine(db_url)
43
+
44
+ # Test connection
45
+ with engine.connect() as conn:
46
+ conn.execute("SELECT 1")
47
+
48
+ return engine
49
+ except Exception as e:
50
+ print(f"Error connecting to customer database: {str(e)}")
51
+ return None
52
+
53
+ def create_tables(self):
54
+ """Create necessary tables in customer's database"""
55
+ engine = self.get_db_engine()
56
+ if not engine:
57
+ return False
58
+
59
+ try:
60
+ # Create tables
61
+ Base.metadata.create_all(engine)
62
+ return True
63
+ except Exception as e:
64
+ print(f"Error creating tables: {str(e)}")
65
+ return False
66
+
67
+ def get_call_records(self, start_date=None, end_date=None):
68
+ """Get call records for this customer"""
69
+ engine = self.get_db_engine()
70
+ if not engine:
71
+ return []
72
+
73
+ try:
74
+ Session = sessionmaker(bind=engine)
75
+ session = Session()
76
+
77
+ query = session.query(CallRecord).filter(CallRecord.customer_id == self.id)
78
+
79
+ if start_date:
80
+ query = query.filter(CallRecord.created_at >= start_date)
81
+ if end_date:
82
+ query = query.filter(CallRecord.created_at <= end_date)
83
+
84
+ records = query.all()
85
+ session.close()
86
+ return records
87
+ except Exception as e:
88
+ print(f"Error getting call records: {str(e)}")
89
+ return []
90
+
91
+ def get_call_details(self, call_id):
92
+ """Get details of a specific call"""
93
+ engine = self.get_db_engine()
94
+ if not engine:
95
+ return None
96
+
97
+ try:
98
+ Session = sessionmaker(bind=engine)
99
+ session = Session()
100
+
101
+ record = session.query(CallRecord).filter(
102
+ CallRecord.id == call_id,
103
+ CallRecord.customer_id == self.id
104
+ ).first()
105
+
106
+ session.close()
107
+ return record
108
+ except Exception as e:
109
+ print(f"Error getting call details: {str(e)}")
110
+ return None
111
+
112
+ def search_calls(self, query):
113
+ """Search calls with custom query"""
114
+ engine = self.get_db_engine()
115
+ if not engine:
116
+ return []
117
+
118
+ try:
119
+ Session = sessionmaker(bind=engine)
120
+ session = Session()
121
+
122
+ # Implement search logic here
123
+ # This is a basic example
124
+ records = session.query(CallRecord).filter(
125
+ CallRecord.customer_id == self.id,
126
+ CallRecord.transcription.ilike(f"%{query}%")
127
+ ).all()
128
+
129
+ session.close()
130
+ return records
131
+ except Exception as e:
132
+ print(f"Error searching calls: {str(e)}")
133
+ return []
134
+
135
  def get_db_url(self) -> Optional[str]:
136
  """Get database URL if credentials are configured"""
137
  if all([self.db_host, self.db_port, self.db_name, self.db_user, self.db_password]):
 
192
  class CallRecord(Base):
193
  __tablename__ = "call_records"
194
 
195
+ id = Column(String(255), primary_key=True)
196
+ customer_id = Column(Integer, nullable=False)
197
+ caller_number = Column(String(255), nullable=False)
198
+ called_number = Column(String(255), nullable=False)
199
+ file_path = Column(String(255), nullable=False)
200
+ transcription = Column(String(10000))
201
+ summary = Column(String(1000))
202
+ sentiment = Column(String(50))
 
203
  created_at = Column(DateTime, default=datetime.utcnow)
204
  updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
205
 
app/static/admin.html CHANGED
@@ -9,6 +9,7 @@
9
  .container { max-width: 800px; margin-top: 2rem; }
10
  .customer-list { margin-top: 2rem; }
11
  .token-section { margin-bottom: 2rem; }
 
12
  </style>
13
  </head>
14
  <body>
@@ -16,7 +17,7 @@
16
  <h1 class="mb-4">vBot Admin Interface</h1>
17
 
18
  <!-- Login Section -->
19
- <div class="card token-section">
20
  <div class="card-body">
21
  <h5 class="card-title">Admin Login</h5>
22
  <form id="loginForm">
@@ -34,46 +35,65 @@
34
  </div>
35
  </div>
36
 
37
- <!-- Add Customer Section -->
38
- <div class="card">
39
- <div class="card-body">
40
- <h5 class="card-title">Add New Customer</h5>
41
- <form id="customerForm">
42
- <div class="mb-3">
43
- <label for="name" class="form-label">Name</label>
44
- <input type="text" class="form-control" id="name" required>
45
- </div>
46
- <div class="mb-3">
47
- <label for="company_name" class="form-label">Company Name</label>
48
- <input type="text" class="form-control" id="company_name" required>
49
- </div>
50
- <div class="mb-3">
51
- <label for="email" class="form-label">Email</label>
52
- <input type="email" class="form-control" id="email" required>
53
- </div>
54
- <button type="submit" class="btn btn-success">Add Customer</button>
55
- </form>
56
- <div id="customerStatus" class="mt-3"></div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  </div>
58
- </div>
59
 
60
- <!-- Customer List Section -->
61
- <div class="card customer-list">
62
- <div class="card-body">
63
- <h5 class="card-title">Customer List</h5>
64
- <div id="customerList" class="table-responsive">
65
- <table class="table">
66
- <thead>
67
- <tr>
68
- <th>Name</th>
69
- <th>Company</th>
70
- <th>Email</th>
71
- <th>API Key</th>
72
- <th>Status</th>
73
- </tr>
74
- </thead>
75
- <tbody id="customerTableBody"></tbody>
76
- </table>
 
77
  </div>
78
  </div>
79
  </div>
@@ -102,6 +122,9 @@
102
  accessToken = data.access_token;
103
  document.getElementById('tokenStatus').innerHTML =
104
  '<div class="alert alert-success">Login successful!</div>';
 
 
 
105
  loadCustomers();
106
  } else {
107
  document.getElementById('tokenStatus').innerHTML =
@@ -125,7 +148,11 @@
125
  const customerData = {
126
  name: document.getElementById('name').value,
127
  company_name: document.getElementById('company_name').value,
128
- email: document.getElementById('email').value
 
 
 
 
129
  };
130
 
131
  try {
@@ -209,11 +236,6 @@
209
  `;
210
  }
211
  }
212
-
213
- // Initial load if token exists
214
- if (accessToken) {
215
- loadCustomers();
216
- }
217
  </script>
218
  </body>
219
  </html>
 
9
  .container { max-width: 800px; margin-top: 2rem; }
10
  .customer-list { margin-top: 2rem; }
11
  .token-section { margin-bottom: 2rem; }
12
+ .hidden { display: none; }
13
  </style>
14
  </head>
15
  <body>
 
17
  <h1 class="mb-4">vBot Admin Interface</h1>
18
 
19
  <!-- Login Section -->
20
+ <div class="card token-section" id="loginSection">
21
  <div class="card-body">
22
  <h5 class="card-title">Admin Login</h5>
23
  <form id="loginForm">
 
35
  </div>
36
  </div>
37
 
38
+ <!-- Main Content (Hidden until login) -->
39
+ <div id="mainContent" class="hidden">
40
+ <!-- Add Customer Section -->
41
+ <div class="card">
42
+ <div class="card-body">
43
+ <h5 class="card-title">Add New Customer</h5>
44
+ <form id="customerForm">
45
+ <div class="mb-3">
46
+ <label for="name" class="form-label">Name</label>
47
+ <input type="text" class="form-control" id="name" required>
48
+ </div>
49
+ <div class="mb-3">
50
+ <label for="company_name" class="form-label">Company Name</label>
51
+ <input type="text" class="form-control" id="company_name" required>
52
+ </div>
53
+ <div class="mb-3">
54
+ <label for="email" class="form-label">Email</label>
55
+ <input type="email" class="form-control" id="email" required>
56
+ </div>
57
+ <div class="mb-3">
58
+ <label for="db_host" class="form-label">Database Host</label>
59
+ <input type="text" class="form-control" id="db_host" required>
60
+ </div>
61
+ <div class="mb-3">
62
+ <label for="db_user" class="form-label">Database Username</label>
63
+ <input type="text" class="form-control" id="db_user" required>
64
+ </div>
65
+ <div class="mb-3">
66
+ <label for="db_password" class="form-label">Database Password</label>
67
+ <input type="password" class="form-control" id="db_password" required>
68
+ </div>
69
+ <div class="mb-3">
70
+ <label for="db_name" class="form-label">Database Name</label>
71
+ <input type="text" class="form-control" id="db_name" required>
72
+ </div>
73
+ <button type="submit" class="btn btn-success">Add Customer</button>
74
+ </form>
75
+ <div id="customerStatus" class="mt-3"></div>
76
+ </div>
77
  </div>
 
78
 
79
+ <!-- Customer List Section -->
80
+ <div class="card customer-list">
81
+ <div class="card-body">
82
+ <h5 class="card-title">Customer List</h5>
83
+ <div id="customerList" class="table-responsive">
84
+ <table class="table">
85
+ <thead>
86
+ <tr>
87
+ <th>Name</th>
88
+ <th>Company</th>
89
+ <th>Email</th>
90
+ <th>API Key</th>
91
+ <th>Status</th>
92
+ </tr>
93
+ </thead>
94
+ <tbody id="customerTableBody"></tbody>
95
+ </table>
96
+ </div>
97
  </div>
98
  </div>
99
  </div>
 
122
  accessToken = data.access_token;
123
  document.getElementById('tokenStatus').innerHTML =
124
  '<div class="alert alert-success">Login successful!</div>';
125
+ // Show main content and hide login section
126
+ document.getElementById('loginSection').classList.add('hidden');
127
+ document.getElementById('mainContent').classList.remove('hidden');
128
  loadCustomers();
129
  } else {
130
  document.getElementById('tokenStatus').innerHTML =
 
148
  const customerData = {
149
  name: document.getElementById('name').value,
150
  company_name: document.getElementById('company_name').value,
151
+ email: document.getElementById('email').value,
152
+ db_host: document.getElementById('db_host').value,
153
+ db_user: document.getElementById('db_user').value,
154
+ db_password: document.getElementById('db_password').value,
155
+ db_name: document.getElementById('db_name').value
156
  };
157
 
158
  try {
 
236
  `;
237
  }
238
  }
 
 
 
 
 
239
  </script>
240
  </body>
241
  </html>