User
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
from datetime import datetime, timezone
|
||||
from app.extensions import db
|
||||
from werkzeug.security import generate_password_hash, check_password_hash
|
||||
|
||||
|
||||
class User(db.Model):
|
||||
__tablename__ = 'users'
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
||||
username = db.Column(db.String(50), unique=True, nullable=False)
|
||||
password_hash = db.Column(db.String(255), nullable=False)
|
||||
name = db.Column(db.String(100), nullable=False)
|
||||
created_at = db.Column(db.DateTime, default=datetime.now(timezone.utc))
|
||||
updated_at = db.Column(db.DateTime, default=datetime.now(timezone.utc), onupdate=datetime.now(timezone.utc))
|
||||
|
||||
def __repr__(self):
|
||||
return f'<User {self.username}>'
|
||||
|
||||
def set_password(self, password):
|
||||
self.password_hash = generate_password_hash(password)
|
||||
|
||||
def check_password(self, password):
|
||||
return check_password_hash(self.password_hash, password)
|
||||
|
||||
@classmethod
|
||||
def create_user(cls, username, password, name):
|
||||
# Check if user already exists
|
||||
if cls.query.filter_by(username=username).first():
|
||||
raise ValueError("Username already exists")
|
||||
|
||||
user = cls(
|
||||
username=username,
|
||||
name=name
|
||||
)
|
||||
user.set_password(password)
|
||||
|
||||
try:
|
||||
db.session.add(user)
|
||||
db.session.commit()
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
raise ValueError(f"Error creating user: {str(e)}")
|
||||
|
||||
return user
|
||||
|
||||
@classmethod
|
||||
def get_user_by_username(cls, username):
|
||||
return cls.query.filter_by(username=username).first()
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'id': self.id,
|
||||
'username': self.username,
|
||||
'name': self.name,
|
||||
'created_at': self.created_at.isoformat() if self.created_at else None,
|
||||
'updated_at': self.updated_at.isoformat() if self.updated_at else None
|
||||
}
|
||||
@@ -58,6 +58,9 @@
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"/login": {
|
||||
"$ref": "../swagger/paths/Login.json"
|
||||
},
|
||||
"/Authorize": {
|
||||
"$ref": "../swagger/paths/Authorize.json"
|
||||
},
|
||||
@@ -88,6 +91,12 @@
|
||||
"AuthorizeRefreshRequest": {
|
||||
"$ref": "../swagger/schemas/AuthorizeRefreshRequest.json"
|
||||
},
|
||||
"LoginRequest": {
|
||||
"$ref": "../swagger/schemas/LoginRequest.json"
|
||||
},
|
||||
"LoginResponse": {
|
||||
"$ref": "../swagger/schemas/LoginResponse.json"
|
||||
},
|
||||
"LoansResponse": {
|
||||
"$ref": "../swagger/schemas/LoansResponse.json"
|
||||
},
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<stringProp name="HTTPSampler.implementation"></stringProp>
|
||||
</ConfigTestElement>
|
||||
<hashTree/>
|
||||
<Arguments guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
|
||||
<Arguments guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables">
|
||||
<collectionProp name="Arguments.arguments">
|
||||
<elementProp name="customer_id" elementType="Argument">
|
||||
<stringProp name="Argument.name">customer_id</stringProp>
|
||||
@@ -60,18 +60,18 @@
|
||||
</collectionProp>
|
||||
</Arguments>
|
||||
<hashTree/>
|
||||
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Loan Endpoint Test" enabled="true">
|
||||
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Loan Endpoint Test">
|
||||
<intProp name="ThreadGroup.num_threads">10</intProp>
|
||||
<intProp name="ThreadGroup.ramp_time">5</intProp>
|
||||
<intProp name="ThreadGroup.ramp_time">1</intProp>
|
||||
<boolProp name="ThreadGroup.same_user_on_next_iteration">true</boolProp>
|
||||
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
|
||||
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller">
|
||||
<stringProp name="LoopController.loops">10</stringProp>
|
||||
<stringProp name="LoopController.loops">1</stringProp>
|
||||
<boolProp name="LoopController.continue_forever">false</boolProp>
|
||||
</elementProp>
|
||||
</ThreadGroup>
|
||||
<hashTree>
|
||||
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Get All Loans">
|
||||
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Get All Loans" enabled="true">
|
||||
<stringProp name="HTTPSampler.path">/loans</stringProp>
|
||||
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
|
||||
<stringProp name="HTTPSampler.method">GET</stringProp>
|
||||
@@ -102,7 +102,7 @@
|
||||
</JSONPathAssertion>
|
||||
<hashTree/>
|
||||
</hashTree>
|
||||
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Get Loans with Filters">
|
||||
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Get Loans with Filters" enabled="true">
|
||||
<stringProp name="HTTPSampler.path">/loans</stringProp>
|
||||
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
|
||||
<stringProp name="HTTPSampler.method">GET</stringProp>
|
||||
@@ -128,7 +128,7 @@
|
||||
</elementProp>
|
||||
</HTTPSamplerProxy>
|
||||
<hashTree>
|
||||
<ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Code Assertion">
|
||||
<ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Code Assertion" enabled="true">
|
||||
<collectionProp name="Asserion.test_strings">
|
||||
<stringProp name="49586">200</stringProp>
|
||||
</collectionProp>
|
||||
@@ -138,7 +138,7 @@
|
||||
<intProp name="Assertion.test_type">8</intProp>
|
||||
</ResponseAssertion>
|
||||
<hashTree/>
|
||||
<JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Path Assertion">
|
||||
<JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Path Assertion" enabled="true">
|
||||
<stringProp name="JSON_PATH">$.loans</stringProp>
|
||||
<stringProp name="EXPECTED_VALUE"></stringProp>
|
||||
<boolProp name="JSONVALIDATION">false</boolProp>
|
||||
@@ -148,7 +148,7 @@
|
||||
</JSONPathAssertion>
|
||||
<hashTree/>
|
||||
</hashTree>
|
||||
<ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="View Results Tree">
|
||||
<ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="View Results Tree" enabled="true">
|
||||
<boolProp name="ResultCollector.error_logging">false</boolProp>
|
||||
<objProp>
|
||||
<name>saveConfig</name>
|
||||
@@ -185,7 +185,7 @@
|
||||
<stringProp name="filename"></stringProp>
|
||||
</ResultCollector>
|
||||
<hashTree/>
|
||||
<ResultCollector guiclass="SummaryReport" testclass="ResultCollector" testname="Summary Report">
|
||||
<ResultCollector guiclass="SummaryReport" testclass="ResultCollector" testname="Summary Report" enabled="true">
|
||||
<boolProp name="ResultCollector.error_logging">false</boolProp>
|
||||
<objProp>
|
||||
<name>saveConfig</name>
|
||||
@@ -298,7 +298,7 @@
|
||||
</elementProp>
|
||||
</HTTPSamplerProxy>
|
||||
<hashTree>
|
||||
<ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Code Assertion" enabled="true">
|
||||
<ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Code Assertion">
|
||||
<collectionProp name="Asserion.test_strings">
|
||||
<stringProp name="49586">200</stringProp>
|
||||
</collectionProp>
|
||||
@@ -308,7 +308,7 @@
|
||||
<intProp name="Assertion.test_type">8</intProp>
|
||||
</ResponseAssertion>
|
||||
<hashTree/>
|
||||
<JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Path Assertion" enabled="true">
|
||||
<JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion" testname="JSON Path Assertion">
|
||||
<stringProp name="JSON_PATH">$.transactions</stringProp>
|
||||
<stringProp name="EXPECTED_VALUE"></stringProp>
|
||||
<boolProp name="JSONVALIDATION">false</boolProp>
|
||||
@@ -355,7 +355,7 @@
|
||||
<stringProp name="filename"></stringProp>
|
||||
</ResultCollector>
|
||||
<hashTree/>
|
||||
<ResultCollector guiclass="SummaryReport" testclass="ResultCollector" testname="Summary Report" enabled="true">
|
||||
<ResultCollector guiclass="SummaryReport" testclass="ResultCollector" testname="Summary Report">
|
||||
<boolProp name="ResultCollector.error_logging">false</boolProp>
|
||||
<objProp>
|
||||
<name>saveConfig</name>
|
||||
|
||||
Reference in New Issue
Block a user