Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Containerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ RUN chown -R tools:tools /app
COPY feedback_exporter feedback_exporter
COPY data_scraper data_scraper
COPY evaluation evaluation
COPY chatbot_db chatbot_db
COPY pdm.lock pyproject.toml Makefile .
RUN make install-pdm install-global

Expand Down
17 changes: 17 additions & 0 deletions chatbot_db/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# User and Token creation script for RCAccelerator

This Python script creates a user and an associated access token in a PostgreSQL database, based on a schema with `users` and `tokens` tables. It is designed for RCAccelerator, to be interactive and secure, using bcrypt for password hashing.

Run the script:

```bash
python add_user.py
```

You will be prompted for:

* The PostgreSQL DATABASE_URL (format: postgresql://user:pass@host:port/dbname)
* The username and email of the user
* The password (input hidden)

A hashed password will be stored in the users table, and a 30-days token will be created in the tokens table.
Empty file added chatbot_db/__init__.py
Empty file.
77 changes: 77 additions & 0 deletions chatbot_db/add_user.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
"""
Tool to add new users to the chatbot database with authentication tokens.
Handles user creation and token generation with secure password hashing.
"""
import uuid
import getpass
import sys
from datetime import datetime, timedelta, UTC

import bcrypt
from sqlalchemy import create_engine, Column, String, TIMESTAMP, Table, MetaData, select, exc
from sqlalchemy.dialects.postgresql import UUID

def main():
"""Entry point for chatbot_db module."""
database_url = input("Enter your DATABASE URL "
"(e.g. postgresql://user:pass@host:port/db): ").strip()
username = input("Enter username: ").strip()
email = input("Enter email: ").strip()
password = getpass.getpass("Enter password (will be hashed): ")
password_hash = bcrypt.hashpw(password.encode("utf-8"), bcrypt.gensalt()).decode("utf-8")
engine = create_engine(database_url)
metadata = MetaData()
users = Table(
"users", metadata,
Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4),
Column("username", String(150), nullable=False, unique=True),
Column("password_hash", String(255), nullable=False),
Column("email", String(150), nullable=False)
)
tokens = Table(
"tokens", metadata,
Column("token", String(64), primary_key=True),
Column("username", String(50)),
Column("created_at", TIMESTAMP, default=datetime.now(UTC)),
Column("expires_at", TIMESTAMP, nullable=False)
)
metadata.create_all(engine)
with engine.connect() as conn:
user_exists = conn.execute(
select(users.c.username).where(users.c.username == username)
).fetchone()

if user_exists:
print(f"Error: User '{username}' already exists. Please choose a different username.")
sys.exit(1)

try:
with engine.begin() as conn:
user_id = uuid.uuid4()
conn.execute(users.insert().values(
id=user_id,
username=username,
password_hash=password_hash,
email=email
))

token_value = uuid.uuid4().hex
conn.execute(tokens.insert().values(
token=token_value,
username=username,
created_at=datetime.now(UTC),
expires_at=datetime.now(UTC) + timedelta(days=30)
))

print(f"\n User '{username}' created with token: {token_value}")
except exc.IntegrityError as e:
print("Error: Database integrity error occurred. User may already exist or "
"there's a constraint violation.")
print(f"Details: {str(e)}")
sys.exit(1)
except (ConnectionError, TimeoutError) as e:
print(f"Error: An unexpected error occurred: {str(e)}")
sys.exit(1)

if __name__ == "__main__":
main()
40 changes: 39 additions & 1 deletion pdm.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ dependencies = [
"requests-kerberos>=0.15.0",
"browser-cookie3>=0.19.1",
"httpx-gssapi>=0.2.0",
"bcrypt>=4.3.0",
]
requires-python = "==3.12.*"

Expand All @@ -42,6 +43,7 @@ feedback_exporter = "feedback_exporter.export_feedback:main"
evaluation = "evaluation.evaluation:main"
osp_doc_scraper = "data_scraper.main:osp_doc_scraper"
solutions_scraper = "data_scraper.main:solutions_scraper"
chatbot_db = "chatbot_db:main"

[tool.setuptools.packages.find]
include = ["data_scraper*", "feedback_exporter*"]
Expand Down
4 changes: 2 additions & 2 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ commands =
description = run Pylint
commands =
{[testenv]commands}
pylint {posargs:./data_scraper ./feedback_exporter ./evaluation}
pylint {posargs:./data_scraper ./feedback_exporter ./evaluation ./chatbot_db}

[testenv:ruff]
description = run ruff
commands =
{[testenv]commands}
ruff check {posargs:./data_scraper ./feedback_exporter ./evaluation}
ruff check {posargs:./data_scraper ./feedback_exporter ./evaluation ./chatbot_db}
Loading