Devices have replaced Clients for authentication as well as location using sections.
Printing of reports done. Main section is now a fixture User and Devices list gives last login details.
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
"""devices
|
||||
|
||||
Revision ID: 00878740057e
|
||||
Revises: 8c06ac60d125
|
||||
Create Date: 2020-10-27 14:02:39.859733
|
||||
|
||||
"""
|
||||
import sqlalchemy as sa
|
||||
|
||||
from alembic import op
|
||||
from sqlalchemy import column, table
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "00878740057e"
|
||||
down_revision = "8c06ac60d125"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table(
|
||||
"login_history",
|
||||
sa.Column("login_history_id", postgresql.UUID(as_uuid=True), nullable=False),
|
||||
sa.Column("user_id", postgresql.UUID(as_uuid=True), nullable=False),
|
||||
sa.Column("device_id", postgresql.UUID(as_uuid=True), nullable=False),
|
||||
sa.Column("date", sa.DateTime(timezone=True), nullable=False),
|
||||
sa.ForeignKeyConstraint(["device_id"], ["devices.id"], name=op.f("fk_login_history_device_id_devices")),
|
||||
sa.ForeignKeyConstraint(["user_id"], ["users.id"], name=op.f("fk_login_history_user_id_users")),
|
||||
sa.PrimaryKeyConstraint("login_history_id", name=op.f("pk_login_history")),
|
||||
sa.UniqueConstraint("user_id", "device_id", "date", name=op.f("uq_login_history_user_id")),
|
||||
)
|
||||
op.drop_table("clients")
|
||||
op.add_column("devices", sa.Column("enabled", sa.Boolean(), nullable=False))
|
||||
op.add_column("devices", sa.Column("creation_date", sa.DateTime(timezone=True), nullable=False))
|
||||
op.alter_column("food_tables", "seats", existing_type=sa.NUMERIC(), type_=sa.Integer(), existing_nullable=False)
|
||||
op.alter_column(
|
||||
"food_tables", "sort_order", existing_type=sa.NUMERIC(), type_=sa.Integer(), existing_nullable=False
|
||||
)
|
||||
op.alter_column(
|
||||
"menu_categories", "sort_order", existing_type=sa.NUMERIC(), type_=sa.Integer(), existing_nullable=False
|
||||
)
|
||||
op.alter_column(
|
||||
"modifier_categories", "sort_order", existing_type=sa.NUMERIC(), type_=sa.Integer(), existing_nullable=False
|
||||
)
|
||||
op.alter_column("products", "sort_order", existing_type=sa.NUMERIC(), type_=sa.Integer(), existing_nullable=False)
|
||||
op.add_column("sections", sa.Column("is_fixture", sa.Boolean(), nullable=True))
|
||||
section = table("sections", column("id", postgresql.UUID(as_uuid=True)), column("is_fixture", sa.Boolean()))
|
||||
op.execute(
|
||||
section.update()
|
||||
.where(section.c.id == op.inline_literal("3f13f6e7-dc76-4fca-8fdb-b2bbf29b35df"))
|
||||
.values({"is_fixture": op.inline_literal(True)})
|
||||
)
|
||||
op.execute(
|
||||
section.update()
|
||||
.where(section.c.id != op.inline_literal("3f13f6e7-dc76-4fca-8fdb-b2bbf29b35df"))
|
||||
.values({"is_fixture": op.inline_literal(False)})
|
||||
)
|
||||
op.alter_column("sections", "is_fixture", nullable=False)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_column("sections", "is_fixture")
|
||||
op.alter_column("products", "sort_order", existing_type=sa.Integer(), type_=sa.NUMERIC(), existing_nullable=False)
|
||||
op.alter_column(
|
||||
"modifier_categories", "sort_order", existing_type=sa.Integer(), type_=sa.NUMERIC(), existing_nullable=False
|
||||
)
|
||||
op.alter_column(
|
||||
"menu_categories", "sort_order", existing_type=sa.Integer(), type_=sa.NUMERIC(), existing_nullable=False
|
||||
)
|
||||
op.alter_column(
|
||||
"food_tables", "sort_order", existing_type=sa.Integer(), type_=sa.NUMERIC(), existing_nullable=False
|
||||
)
|
||||
op.alter_column("food_tables", "seats", existing_type=sa.Integer(), type_=sa.NUMERIC(), existing_nullable=False)
|
||||
op.drop_column("devices", "enabled")
|
||||
op.create_table(
|
||||
"clients",
|
||||
sa.Column("id", sa.INTEGER(), autoincrement=True, nullable=False),
|
||||
sa.Column("name", sa.VARCHAR(length=255), autoincrement=False, nullable=False),
|
||||
sa.Column("enabled", sa.BOOLEAN(), autoincrement=False, nullable=False),
|
||||
sa.Column("otp", sa.INTEGER(), autoincrement=False, nullable=True),
|
||||
sa.Column("creation_date", postgresql.TIMESTAMP(timezone=True), autoincrement=False, nullable=False),
|
||||
sa.PrimaryKeyConstraint("id", name="pk_clients"),
|
||||
sa.UniqueConstraint("name", name="uq_clients_name"),
|
||||
)
|
||||
op.drop_table("login_history")
|
||||
# ### end Alembic commands ###
|
||||
@@ -466,6 +466,8 @@ def upgrade():
|
||||
op.execute(Permission.__table__.insert().values(id="5b66c6f6-003a-4ef8-ba28-49b8ff1ac33c", name="Printers"))
|
||||
op.execute(Permission.__table__.insert().values(id="c973f32c-a37b-496a-8dc5-60d2e4c39e97", name="Sections"))
|
||||
op.execute(Permission.__table__.insert().values(id="7a04ba63-5d08-4078-9051-a6d91cce3e48", name="Section Printers"))
|
||||
op.execute(Permission.__table__.insert().values(id="d4e1d14f-f2c2-4728-9303-a0d8c74c5ea1", name="Devices"))
|
||||
op.execute(Permission.__table__.insert().values(id="5f6110ba-2d3a-41cb-9597-1157774f10cb", name="Add Devices"))
|
||||
op.execute(Section.__table__.insert().values(id="3f13f6e7-dc76-4fca-8fdb-b2bbf29b35df", name="Main"))
|
||||
|
||||
op.execute(
|
||||
|
||||
@@ -13,7 +13,7 @@ from sqlalchemy.orm import Session
|
||||
|
||||
from ..core.config import settings
|
||||
from ..db.session import SessionLocal
|
||||
from ..models.auth import Client
|
||||
from ..models.auth import Device
|
||||
from ..models.auth import User as UserModel
|
||||
|
||||
# to get a string like this run:
|
||||
@@ -69,29 +69,18 @@ def get_user(username: str, id_: str, locked_out: bool, scopes: List[str]) -> Us
|
||||
)
|
||||
|
||||
|
||||
def authenticate_user(
|
||||
username: str, password: str, client_id: Optional[int], otp: int, db: Session
|
||||
) -> Optional[UserModel]:
|
||||
def authenticate_user(username: str, password: str, db: Session) -> Optional[UserModel]:
|
||||
user = UserModel.auth(username, password, db)
|
||||
return user
|
||||
|
||||
|
||||
def client_allowed(user: UserModel, client_id: int, otp: Optional[int] = None, db: Session = None) -> (bool, int):
|
||||
client = db.query(Client).filter(Client.id == client_id).first() if client_id else None
|
||||
allowed = "clients" in set([p.name.replace(" ", "-").lower() for r in user.roles for p in r.permissions])
|
||||
if allowed or True:
|
||||
return True, 0
|
||||
elif client is None:
|
||||
client = Client.create(db)
|
||||
return False, client.id
|
||||
elif client.enabled:
|
||||
return True, client.id
|
||||
elif client.otp == otp:
|
||||
client.otp = None
|
||||
client.enabled = True
|
||||
return True, client.id
|
||||
else:
|
||||
return False, client.id
|
||||
def device_allowed(user: UserModel, device_id: Optional[uuid.UUID], db: Session = None) -> (bool, Device):
|
||||
device: Device = db.query(Device).filter(Device.id == device_id).first()
|
||||
if device is None:
|
||||
device = Device.create(db)
|
||||
allowed = "add-devices" in set([p.name.replace(" ", "-").lower() for r in user.roles for p in r.permissions])
|
||||
|
||||
return allowed or device.enabled, device
|
||||
|
||||
|
||||
async def get_current_user(
|
||||
|
||||
@@ -7,6 +7,7 @@ from .core.config import settings
|
||||
from .db.base_class import Base
|
||||
from .db.session import engine
|
||||
from .routers import (
|
||||
device,
|
||||
guest_book,
|
||||
login,
|
||||
menu_category,
|
||||
@@ -20,7 +21,7 @@ from .routers import (
|
||||
table,
|
||||
tax,
|
||||
)
|
||||
from .routers.auth import client, role, user
|
||||
from .routers.auth import role, user
|
||||
from .routers.reports import (
|
||||
beer_consumption_report,
|
||||
bill_settlement_report,
|
||||
@@ -50,7 +51,6 @@ app = FastAPI()
|
||||
app.add_middleware(SessionMiddleware, secret_key=settings.MIDDLEWARE_SECRET_KEY)
|
||||
|
||||
app.include_router(login.router, tags=["login"])
|
||||
app.include_router(client.router, prefix="/api/clients", tags=["clients"])
|
||||
app.include_router(role.router, prefix="/api/roles", tags=["users"])
|
||||
app.include_router(user.router, prefix="/api/users", tags=["users"])
|
||||
|
||||
@@ -61,6 +61,7 @@ app.include_router(printer.router, prefix="/api/printers", tags=["printers"])
|
||||
|
||||
app.include_router(menu_category.router, prefix="/api/menu-categories", tags=["products"])
|
||||
app.include_router(product.router, prefix="/api/products", tags=["products"])
|
||||
app.include_router(device.router, prefix="/api/devices", tags=["devices"])
|
||||
app.include_router(sale_category.router, prefix="/api/sale-categories", tags=["products"])
|
||||
|
||||
app.include_router(section.router, prefix="/api/sections", tags=["sections"])
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
from sqlalchemy import engine_from_config
|
||||
from sqlalchemy.orm import configure_mappers, sessionmaker
|
||||
|
||||
from .auth import Client, Permission, Role, User, role_permissions, user_roles
|
||||
from .auth import Device, Permission, Role, User, role_permissions, user_roles
|
||||
from .master import (
|
||||
Customer,
|
||||
DbSetting,
|
||||
Device,
|
||||
FoodTable,
|
||||
MenuCategory,
|
||||
Modifier,
|
||||
|
||||
@@ -5,7 +5,7 @@ import uuid
|
||||
from datetime import datetime
|
||||
from hashlib import md5
|
||||
|
||||
from sqlalchemy import Boolean, Column, DateTime, Integer, Unicode, UniqueConstraint
|
||||
from sqlalchemy import Boolean, Column, DateTime, Unicode, UniqueConstraint, desc
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import Session, relationship, synonym
|
||||
from sqlalchemy.schema import ForeignKey, Table
|
||||
@@ -17,38 +17,52 @@ def encrypt(val):
|
||||
return md5(val.encode("utf-8") + "v2".encode("utf-8")).hexdigest()
|
||||
|
||||
|
||||
class Client(Base):
|
||||
__tablename__ = "clients"
|
||||
class LoginHistory(Base):
|
||||
__tablename__ = "login_history"
|
||||
__table_args__ = (UniqueConstraint("user_id", "device_id", "date"),)
|
||||
id = Column("login_history_id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
user_id = Column("user_id", UUID(as_uuid=True), ForeignKey("users.id"), nullable=False)
|
||||
device_id = Column(
|
||||
"device_id",
|
||||
UUID(as_uuid=True),
|
||||
ForeignKey("devices.id"),
|
||||
nullable=False,
|
||||
)
|
||||
date = Column("date", DateTime(timezone=True), nullable=False)
|
||||
|
||||
id = Column("id", Integer, primary_key=True)
|
||||
def __init__(self, user_id=None, device_id=None, date=None, id_=None):
|
||||
self.user_id = user_id
|
||||
self.device_id = device_id
|
||||
self.date = datetime.utcnow() if date is None else date
|
||||
self.id = id_
|
||||
|
||||
|
||||
class Device(Base):
|
||||
__tablename__ = "devices"
|
||||
|
||||
id = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
name = Column("name", Unicode(255), unique=True, nullable=False)
|
||||
enabled = Column("enabled", Boolean, nullable=False)
|
||||
otp = Column("otp", Integer)
|
||||
section_id = Column("section_id", UUID(as_uuid=True), ForeignKey("sections.id"), nullable=False)
|
||||
creation_date = Column("creation_date", DateTime(timezone=True), nullable=False)
|
||||
|
||||
def __init__(self, id_=None, name=None, enabled=False, otp=None, creation_date=None):
|
||||
self.id = id_
|
||||
section = relationship("Section", foreign_keys=section_id)
|
||||
login_history = relationship("LoginHistory", order_by=desc(LoginHistory.date), backref="device")
|
||||
|
||||
def __init__(self, name=None, enabled=None, section_id=None, creation_date=None, id_=None):
|
||||
self.name = name
|
||||
self.enabled = enabled
|
||||
self.otp = otp
|
||||
self.creation_date = creation_date or datetime.utcnow()
|
||||
|
||||
@classmethod
|
||||
def by_id(cls, id_: int, db: Session):
|
||||
if id_ is None:
|
||||
return None
|
||||
if not isinstance(id_, int):
|
||||
id_ = int(id_)
|
||||
return db.query(cls).filter(cls.id == id_).first()
|
||||
self.section_id = section_id
|
||||
self.creation_date = datetime.utcnow() if creation_date is None else creation_date
|
||||
self.id = id_
|
||||
|
||||
@classmethod
|
||||
def create(cls, db: Session):
|
||||
client_code = random.randint(1000, 9999)
|
||||
otp = random.randint(1000, 9999)
|
||||
name = "".join(random.choice(string.ascii_uppercase + string.digits) for x in range(6))
|
||||
client = Client(client_code, name, False, otp)
|
||||
db.add(client)
|
||||
return client
|
||||
main_section = uuid.UUID("3f13f6e7-dc76-4fca-8fdb-b2bbf29b35df")
|
||||
name = "".join(random.choices(string.ascii_lowercase + string.digits, k=6))
|
||||
device = Device(name, False, main_section)
|
||||
db.add(device)
|
||||
return device
|
||||
|
||||
|
||||
user_roles = Table(
|
||||
@@ -84,6 +98,7 @@ class User(Base):
|
||||
locked_out = Column("locked_out", Boolean, nullable=False)
|
||||
|
||||
roles = relationship("Role", secondary=user_roles, order_by="Role.name")
|
||||
login_history = relationship("LoginHistory", order_by=desc(LoginHistory.date), backref="user")
|
||||
|
||||
def _get_password(self):
|
||||
return self._password
|
||||
|
||||
@@ -299,25 +299,16 @@ class Section(Base):
|
||||
|
||||
id = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
name = Column("name", Unicode(255), unique=True, nullable=False)
|
||||
is_fixture = Column("is_fixture", Boolean, nullable=False, default=False)
|
||||
|
||||
def __init__(self, name=None, id_=None):
|
||||
def __init__(self, name=None, is_fixture=None, id_=None):
|
||||
self.id = id_
|
||||
self.name = name
|
||||
self.is_fixture = is_fixture
|
||||
|
||||
|
||||
class Device(Base):
|
||||
__tablename__ = "devices"
|
||||
|
||||
id = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
name = Column("name", Unicode(255), unique=True, nullable=False)
|
||||
section_id = Column("section_id", UUID(as_uuid=True), ForeignKey("sections.id"), nullable=False)
|
||||
|
||||
section = relationship("Section", foreign_keys=section_id)
|
||||
|
||||
def __init__(self, name=None, section_id=None, id_=None):
|
||||
self.name = name
|
||||
self.section_id = section_id
|
||||
self.id = id_
|
||||
@classmethod
|
||||
def main(cls):
|
||||
return uuid.UUID("3f13f6e7-dc76-4fca-8fdb-b2bbf29b35df")
|
||||
|
||||
|
||||
class Printer(Base):
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import asyncio
|
||||
import uuid
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
@@ -7,15 +8,16 @@ from barker.schemas.cashier_report import CashierReport
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ..core.arq import settings as redis_settings
|
||||
from ..models import Printer, SectionPrinter
|
||||
from ..models import Device, Printer, SectionPrinter
|
||||
|
||||
|
||||
def print_cashier_report(report: CashierReport, db: Session):
|
||||
def print_cashier_report(report: CashierReport, device_id: uuid.UUID, db: Session):
|
||||
data = design_cashier_report(report)
|
||||
section_id = db.query(Device.section_id).filter(Device.id == device_id).scalar()
|
||||
printer = (
|
||||
db.query(Printer)
|
||||
.join(SectionPrinter.printer)
|
||||
# .filter(SectionPrinter.section_id == voucher.food_table.section_id) TODO: Use device's section_id
|
||||
.filter(SectionPrinter.section_id == section_id)
|
||||
.filter(SectionPrinter.menu_category_id == None) # noqa: E711
|
||||
.first()
|
||||
)
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
import asyncio
|
||||
import uuid
|
||||
|
||||
from arq import ArqRedis, create_pool
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ..core.arq import settings as redis_settings
|
||||
from ..models import Printer, SectionPrinter
|
||||
from ..models import Device, Printer, SectionPrinter
|
||||
from ..schemas.discount_report import DiscountReport
|
||||
|
||||
|
||||
def print_discount_report(report: DiscountReport, db: Session):
|
||||
def print_discount_report(report: DiscountReport, device_id: uuid.UUID, db: Session):
|
||||
data = design_discount_report(report)
|
||||
section_id = db.query(Device.section_id).filter(Device.id == device_id).scalar()
|
||||
printer = (
|
||||
db.query(Printer)
|
||||
.join(SectionPrinter.printer)
|
||||
# .filter(SectionPrinter.section_id == voucher.food_table.section_id) TODO: Use device's section_id
|
||||
.filter(SectionPrinter.section_id == section_id)
|
||||
.filter(SectionPrinter.menu_category_id == None) # noqa: E711
|
||||
.first()
|
||||
)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import asyncio
|
||||
import uuid
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
@@ -6,16 +7,17 @@ from arq import ArqRedis, create_pool
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ..core.arq import settings as redis_settings
|
||||
from ..models import Printer, SectionPrinter
|
||||
from ..models import Device, Printer, SectionPrinter
|
||||
from ..schemas.sale_report import SaleReport
|
||||
|
||||
|
||||
def print_sale_report(report: SaleReport, db: Session):
|
||||
def print_sale_report(report: SaleReport, device_id: uuid.UUID, db: Session):
|
||||
data = design_sale_report(report)
|
||||
section_id = db.query(Device.section_id).filter(Device.id == device_id).scalar()
|
||||
printer = (
|
||||
db.query(Printer)
|
||||
.join(SectionPrinter.printer)
|
||||
# .filter(SectionPrinter.section_id == voucher.food_table.section_id) TODO: Use device's section_id
|
||||
.filter(SectionPrinter.section_id == section_id)
|
||||
.filter(SectionPrinter.menu_category_id == None) # noqa: E711
|
||||
.first()
|
||||
)
|
||||
|
||||
@@ -1,116 +0,0 @@
|
||||
import uuid
|
||||
|
||||
import barker.schemas.auth as schemas
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Security, status
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ...core.security import get_current_active_user as get_user
|
||||
from ...db.session import SessionLocal
|
||||
from ...models.auth import Client
|
||||
from ...schemas.auth import UserToken
|
||||
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
# Dependency
|
||||
def get_db():
|
||||
try:
|
||||
db = SessionLocal()
|
||||
yield db
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
@router.put("/{id_}")
|
||||
def update(
|
||||
id_: uuid.UUID,
|
||||
data: schemas.ClientIn,
|
||||
db: Session = Depends(get_db),
|
||||
user: UserToken = Security(get_user, scopes=["clients"]),
|
||||
):
|
||||
try:
|
||||
item: Client = db.query(Client).filter(Client.id == id_).first()
|
||||
item.enabled = data.enabled
|
||||
if item.enabled:
|
||||
item.otp = None
|
||||
item.name = data.name
|
||||
db.commit()
|
||||
return {}
|
||||
except SQLAlchemyError as e:
|
||||
db.rollback()
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=str(e),
|
||||
)
|
||||
except Exception:
|
||||
db.rollback()
|
||||
raise
|
||||
|
||||
|
||||
@router.delete("/{id_}")
|
||||
def delete(
|
||||
id_: uuid.UUID,
|
||||
db: Session = Depends(get_db),
|
||||
user: UserToken = Security(get_user, scopes=["clients"]),
|
||||
):
|
||||
try:
|
||||
item: Client = db.query(Client).filter(Client.id == id_).first()
|
||||
# db.execute(LoginHistory.__table__.delete(LoginHistory.client_id == item.id))
|
||||
db.delete(item)
|
||||
db.commit()
|
||||
return {}
|
||||
except SQLAlchemyError as e:
|
||||
db.rollback()
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=str(e),
|
||||
)
|
||||
except Exception:
|
||||
db.rollback()
|
||||
raise
|
||||
|
||||
|
||||
@router.get("/list")
|
||||
async def show_list(
|
||||
db: Session = Depends(get_db),
|
||||
user: UserToken = Security(get_user, scopes=["clients"]),
|
||||
):
|
||||
list_ = db.query(Client).order_by(Client.name).all()
|
||||
clients = []
|
||||
for item in list_:
|
||||
# last_login = (
|
||||
# db.query(LoginHistory).filter(LoginHistory.client_id == item.id).order_by(desc(LoginHistory.date)).first()
|
||||
# )
|
||||
# last_login = "Never" if last_login is None else last_login.date.strftime("%d-%b-%Y %H:%M")
|
||||
last_login = "Never"
|
||||
clients.append(
|
||||
{
|
||||
"id": item.id,
|
||||
"code": item.code,
|
||||
"name": item.name,
|
||||
"enabled": item.enabled,
|
||||
"otp": item.otp,
|
||||
"creationDate": item.creation_date.strftime("%d-%b-%Y %H:%M"),
|
||||
"lastLogin": last_login,
|
||||
}
|
||||
)
|
||||
return clients
|
||||
|
||||
|
||||
@router.get("/{id_}")
|
||||
def show_id(
|
||||
id_: uuid.UUID,
|
||||
db: Session = Depends(get_db),
|
||||
user: UserToken = Security(get_user, scopes=["clients"]),
|
||||
):
|
||||
item: Client = db.query(Client).filter(Client.id == id_).first()
|
||||
return {
|
||||
"id": item.id,
|
||||
"code": item.code,
|
||||
"name": item.name,
|
||||
"enabled": item.enabled,
|
||||
"otp": item.otp,
|
||||
}
|
||||
@@ -31,7 +31,7 @@ def save(
|
||||
data: schemas.UserIn,
|
||||
db: Session = Depends(get_db),
|
||||
user: UserToken = Security(get_user, scopes=["users"]),
|
||||
):
|
||||
) -> schemas.User:
|
||||
try:
|
||||
item = User(name=data.name, password=data.password, locked_out=data.locked_out)
|
||||
db.add(item)
|
||||
@@ -53,7 +53,7 @@ def save(
|
||||
def show_me(
|
||||
db: Session = Depends(get_db),
|
||||
user: UserToken = Depends(get_user),
|
||||
):
|
||||
) -> schemas.User:
|
||||
item = db.query(User).filter(User.id == user.id_).first()
|
||||
return user_info(item, db, user)
|
||||
|
||||
@@ -63,7 +63,7 @@ def update_me(
|
||||
data: schemas.UserIn,
|
||||
db: Session = Depends(get_db),
|
||||
user: UserToken = Depends(get_user),
|
||||
):
|
||||
) -> schemas.User:
|
||||
try:
|
||||
item: User = db.query(User).filter(User.id == user.id_).first()
|
||||
if "users" in user.permissions:
|
||||
@@ -91,7 +91,7 @@ def update(
|
||||
data: schemas.UserIn,
|
||||
db: Session = Depends(get_db),
|
||||
user: UserToken = Security(get_user, scopes=["users"]),
|
||||
):
|
||||
) -> schemas.User:
|
||||
try:
|
||||
item: User = db.query(User).filter(User.id == id_).first()
|
||||
item.name = data.name
|
||||
@@ -157,14 +157,16 @@ def show_blank(
|
||||
async def show_list(
|
||||
db: Session = Depends(get_db),
|
||||
user: UserToken = Security(get_user, scopes=["users"]),
|
||||
):
|
||||
) -> List[schemas.UserList]:
|
||||
return [
|
||||
{
|
||||
"id": item.id,
|
||||
"name": item.name,
|
||||
"lockedOut": item.locked_out,
|
||||
"roles": [p.name for p in sorted(item.roles, key=lambda p: p.name)],
|
||||
}
|
||||
schemas.UserList(
|
||||
id=item.id,
|
||||
name=item.name,
|
||||
lockedOut=item.locked_out,
|
||||
roles=[p.name for p in sorted(item.roles, key=lambda p: p.name)],
|
||||
lastDevice=item.login_history[0].device.name if len(item.login_history) else "Never",
|
||||
lastDate=item.login_history[0].date if len(item.login_history) else None,
|
||||
)
|
||||
for item in db.query(User).order_by(User.name).all()
|
||||
]
|
||||
|
||||
@@ -182,25 +184,25 @@ def show_id(
|
||||
id_: uuid.UUID,
|
||||
db: Session = Depends(get_db),
|
||||
user: UserToken = Security(get_user, scopes=["users"]),
|
||||
):
|
||||
) -> schemas.User:
|
||||
item = db.query(User).filter(User.id == id_).first()
|
||||
return user_info(item, db, user)
|
||||
|
||||
|
||||
def user_info(item: Optional[User], db: Session, user: UserToken):
|
||||
def user_info(item: Optional[User], db: Session, user: UserToken) -> schemas.User:
|
||||
if item is None:
|
||||
return {
|
||||
"name": "",
|
||||
"lockedOut": False,
|
||||
"roles": [{"id": r.id, "name": r.name, "enabled": False} for r in db.query(Role).order_by(Role.name).all()],
|
||||
}
|
||||
return schemas.User(
|
||||
name="",
|
||||
lockedOut=False,
|
||||
roles=[{"id": r.id, "name": r.name, "enabled": False} for r in db.query(Role).order_by(Role.name).all()],
|
||||
)
|
||||
else:
|
||||
return {
|
||||
"id": item.id,
|
||||
"name": item.name,
|
||||
"password": "",
|
||||
"lockedOut": item.locked_out,
|
||||
"roles": [
|
||||
return schemas.User(
|
||||
id=item.id,
|
||||
name=item.name,
|
||||
password="",
|
||||
lockedOut=item.locked_out,
|
||||
roles=[
|
||||
{
|
||||
"id": r.id,
|
||||
"name": r.name,
|
||||
@@ -210,4 +212,4 @@ def user_info(item: Optional[User], db: Session, user: UserToken):
|
||||
]
|
||||
if "users" in user.permissions
|
||||
else [],
|
||||
}
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import uuid
|
||||
|
||||
from typing import Optional
|
||||
from typing import List
|
||||
|
||||
import barker.schemas.master as schemas
|
||||
|
||||
@@ -10,7 +10,7 @@ from sqlalchemy.orm import Session
|
||||
|
||||
from ..core.security import get_current_active_user as get_user
|
||||
from ..db.session import SessionLocal
|
||||
from ..models.master import Device
|
||||
from ..models.auth import Device
|
||||
from ..schemas.auth import UserToken
|
||||
|
||||
|
||||
@@ -26,38 +26,17 @@ def get_db():
|
||||
db.close()
|
||||
|
||||
|
||||
@router.post("", response_model=schemas.Device)
|
||||
def save(
|
||||
data: schemas.DeviceIn,
|
||||
db: Session = Depends(get_db),
|
||||
user: UserToken = Security(get_user, scopes=["devices"]),
|
||||
):
|
||||
try:
|
||||
item = Device(name=data.name, section_id=data.section.id_)
|
||||
db.add(item)
|
||||
db.commit()
|
||||
return device_info(item)
|
||||
except SQLAlchemyError as e:
|
||||
db.rollback()
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=str(e),
|
||||
)
|
||||
except Exception:
|
||||
db.rollback()
|
||||
raise
|
||||
|
||||
|
||||
@router.put("/{id_}", response_model=schemas.Device)
|
||||
def update(
|
||||
id_: uuid.UUID,
|
||||
data: schemas.DeviceIn,
|
||||
db: Session = Depends(get_db),
|
||||
user: UserToken = Security(get_user, scopes=["devices"]),
|
||||
):
|
||||
) -> schemas.Device:
|
||||
try:
|
||||
item: Device = db.query(Device).filter(Device.id == id_).first()
|
||||
item.name = data.name
|
||||
item.enabled = data.enabled
|
||||
item.section_id = data.section.id_
|
||||
db.commit()
|
||||
return device_info(item)
|
||||
@@ -72,12 +51,12 @@ def update(
|
||||
raise
|
||||
|
||||
|
||||
@router.delete("/{id_}")
|
||||
@router.delete("/{id_}", response_model=schemas.Device)
|
||||
def delete(
|
||||
id_: uuid.UUID,
|
||||
db: Session = Depends(get_db),
|
||||
user: UserToken = Security(get_user, scopes=["devices"]),
|
||||
):
|
||||
user: UserToken = Security(get_user, scopes=["add-devices"]),
|
||||
) -> schemas.Device:
|
||||
try:
|
||||
item: Device = db.query(Device).filter(Device.id == id_).first()
|
||||
db.delete(item)
|
||||
@@ -94,34 +73,28 @@ def delete(
|
||||
raise
|
||||
|
||||
|
||||
@router.get("")
|
||||
def show_blank(
|
||||
db: Session = Depends(get_db),
|
||||
user: UserToken = Security(get_user, scopes=["devices"]),
|
||||
):
|
||||
return device_info(None)
|
||||
|
||||
|
||||
@router.get("/list")
|
||||
@router.get("/list", response_model=List[schemas.Device])
|
||||
def show_list(db: Session = Depends(get_db), user: UserToken = Depends(get_user)):
|
||||
return [device_info(item) for item in db.query(Device).order_by(Device.name).all()]
|
||||
|
||||
|
||||
@router.get("/{id_}")
|
||||
@router.get("/{id_}", response_model=schemas.Device)
|
||||
def show_id(
|
||||
id_: uuid.UUID,
|
||||
db: Session = Depends(get_db),
|
||||
user: UserToken = Security(get_user, scopes=["devices"]),
|
||||
):
|
||||
) -> schemas.Device:
|
||||
item: Device = db.query(Device).filter(Device.id == id_).first()
|
||||
return device_info(item)
|
||||
|
||||
|
||||
def device_info(item: Optional[Device]):
|
||||
if item is None:
|
||||
return {"name": "", "section": {}}
|
||||
return {
|
||||
"id": item.id,
|
||||
"name": item.name,
|
||||
"section": {"id": item.section_id, "name": item.section.name},
|
||||
}
|
||||
def device_info(item: Device) -> schemas.Device:
|
||||
return schemas.Device(
|
||||
id=item.id,
|
||||
name=item.name,
|
||||
enabled=item.enabled,
|
||||
section={"id": item.section_id, "name": item.section.name},
|
||||
creationDate=item.creation_date,
|
||||
lastUser=item.login_history[0].user.name if len(item.login_history) else "Never",
|
||||
lastDate=item.login_history[0].date if len(item.login_history) else None,
|
||||
)
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import uuid
|
||||
|
||||
from datetime import timedelta
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import (
|
||||
APIRouter,
|
||||
Cookie,
|
||||
Depends,
|
||||
Form,
|
||||
HTTPException,
|
||||
Response,
|
||||
Security,
|
||||
@@ -19,11 +21,12 @@ from ..core.config import settings
|
||||
from ..core.security import (
|
||||
Token,
|
||||
authenticate_user,
|
||||
client_allowed,
|
||||
create_access_token,
|
||||
device_allowed,
|
||||
get_current_active_user,
|
||||
)
|
||||
from ..db.session import SessionLocal
|
||||
from ..models.auth import LoginHistory
|
||||
from ..schemas.auth import UserToken
|
||||
|
||||
|
||||
@@ -43,28 +46,32 @@ def get_db():
|
||||
async def login_for_access_token(
|
||||
response: Response,
|
||||
form_data: OAuth2PasswordRequestForm = Depends(),
|
||||
client_id: int = Cookie(None),
|
||||
otp: int = Form(None),
|
||||
device_id: Optional[uuid.UUID] = Cookie(None),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
user = authenticate_user(form_data.username, form_data.password, client_id, otp, db)
|
||||
user = authenticate_user(form_data.username, form_data.password, db)
|
||||
if not user:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Incorrect username or password",
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
allowed, c_id = client_allowed(user, client_id, otp, db)
|
||||
allowed, device = device_allowed(user, device_id, db)
|
||||
db.flush()
|
||||
if allowed:
|
||||
history = LoginHistory(user.id, device.id)
|
||||
db.add(history)
|
||||
db.commit()
|
||||
if c_id and c_id != client_id:
|
||||
response.set_cookie(key="client_id", value=str(c_id), max_age=10 * 365 * 24 * 60 * 60)
|
||||
response.set_cookie(key="device_id", value=str(device.id), max_age=10 * 365 * 24 * 60 * 60)
|
||||
response.set_cookie(key="device", value=device.name, max_age=10 * 365 * 24 * 60 * 60)
|
||||
if not allowed:
|
||||
not_allowed_response = JSONResponse(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
content={"detail": "Client is not registered"},
|
||||
)
|
||||
not_allowed_response.set_cookie(key="client_id", value=str(c_id), max_age=10 * 365 * 24 * 60 * 60)
|
||||
not_allowed_response.set_cookie(key="device_id", value=str(device.id), max_age=10 * 365 * 24 * 60 * 60)
|
||||
not_allowed_response.set_cookie(key="device", value=device.name, max_age=10 * 365 * 24 * 60 * 60)
|
||||
return not_allowed_response
|
||||
access_token_expires = timedelta(minutes=settings.JWT_TOKEN_EXPIRE_MINUTES)
|
||||
access_token = create_access_token(
|
||||
|
||||
@@ -3,7 +3,7 @@ import uuid
|
||||
from datetime import date, datetime, timedelta
|
||||
from typing import Dict, List
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Security, status
|
||||
from fastapi import APIRouter, Cookie, Depends, HTTPException, Security, status
|
||||
from sqlalchemy import distinct
|
||||
from sqlalchemy.orm import Session, joinedload
|
||||
|
||||
@@ -134,6 +134,7 @@ def print_report(
|
||||
id_: uuid.UUID,
|
||||
s: str = None,
|
||||
f: str = None,
|
||||
device_id: uuid.UUID = Cookie(None),
|
||||
db: Session = Depends(get_db),
|
||||
user: UserToken = Security(get_user, scopes=["cashier-report"]),
|
||||
) -> bool:
|
||||
@@ -144,8 +145,8 @@ def print_report(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="Accounts Audit",
|
||||
)
|
||||
report = get_id(id_, start_date, finish_date, user, db)
|
||||
print_cashier_report(report, db)
|
||||
report = get_id(id_, start_date, finish_date, UserLink(id=user.id_, name=user.name), db)
|
||||
print_cashier_report(report, device_id, db)
|
||||
return True
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import uuid
|
||||
|
||||
from datetime import date, datetime, timedelta
|
||||
from typing import List
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Security, status
|
||||
from fastapi import APIRouter, Cookie, Depends, HTTPException, Security, status
|
||||
from sqlalchemy import func
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
@@ -76,6 +78,7 @@ def get_discount_report(s: date, f: date, db: Session) -> List[DiscountReportIte
|
||||
def print_report(
|
||||
s: str = None,
|
||||
f: str = None,
|
||||
device_id: uuid.UUID = Cookie(None),
|
||||
db: Session = Depends(get_db),
|
||||
user: UserToken = Security(get_user, scopes=["discount-report"]),
|
||||
) -> bool:
|
||||
@@ -91,5 +94,5 @@ def print_report(
|
||||
finishDate=finish_date,
|
||||
amounts=get_discount_report(start_date, finish_date, db),
|
||||
)
|
||||
print_discount_report(report, db)
|
||||
print_discount_report(report, device_id, db)
|
||||
return True
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import uuid
|
||||
|
||||
from datetime import date, datetime, timedelta
|
||||
from typing import List
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Security, status
|
||||
from fastapi import APIRouter, Cookie, Depends, HTTPException, Security, status
|
||||
from sqlalchemy import func
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
@@ -117,6 +119,7 @@ def get_settlements(s: date, f: date, db: Session) -> List[SaleReportItem]:
|
||||
def print_report(
|
||||
s: str = None,
|
||||
f: str = None,
|
||||
device_id: uuid.UUID = Cookie(None),
|
||||
db: Session = Depends(get_db),
|
||||
user: UserToken = Security(get_user, scopes=["discount-report"]),
|
||||
) -> bool:
|
||||
@@ -139,5 +142,5 @@ def print_report(
|
||||
),
|
||||
user=UserLink(id=user.id_, name=user.name),
|
||||
)
|
||||
print_sale_report(report, db)
|
||||
print_sale_report(report, device_id, db)
|
||||
return True
|
||||
|
||||
@@ -57,6 +57,11 @@ def update(
|
||||
):
|
||||
try:
|
||||
item: Section = db.query(Section).filter(Section.id == id_).first()
|
||||
if item.is_fixture:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_423_LOCKED,
|
||||
detail=f"{item.name} is a fixture and cannot be edited or deleted.",
|
||||
)
|
||||
item.name = data.name
|
||||
db.commit()
|
||||
return section_info(item)
|
||||
@@ -79,6 +84,11 @@ def delete(
|
||||
):
|
||||
try:
|
||||
item: Section = db.query(Section).filter(Section.id == id_).first()
|
||||
if item.is_fixture:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_423_LOCKED,
|
||||
detail=f"{item.name} is a fixture and cannot be edited or deleted.",
|
||||
)
|
||||
db.delete(item)
|
||||
db.commit()
|
||||
return section_info(None)
|
||||
|
||||
@@ -101,10 +101,14 @@ class UserList(BaseModel):
|
||||
id_: uuid.UUID
|
||||
name: str
|
||||
roles: List[str]
|
||||
last_device: str
|
||||
last_date: Optional[datetime]
|
||||
|
||||
class Config:
|
||||
fields = {"id_": "id"}
|
||||
anystr_strip_whitespace = True
|
||||
alias_generator = to_camel
|
||||
json_encoders = {datetime: lambda v: v.strftime("%d-%b-%Y %H:%M")}
|
||||
|
||||
|
||||
class UserToken(BaseModel):
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import uuid
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
@@ -10,6 +11,7 @@ from .section import SectionLink
|
||||
|
||||
class DeviceIn(BaseModel):
|
||||
name: str = Field(..., min_length=1)
|
||||
enabled: bool
|
||||
section: SectionLink
|
||||
|
||||
class Config:
|
||||
@@ -19,9 +21,15 @@ class DeviceIn(BaseModel):
|
||||
|
||||
class Device(DeviceIn):
|
||||
id_: uuid.UUID
|
||||
creation_date: datetime
|
||||
last_user: str
|
||||
last_date: Optional[datetime]
|
||||
|
||||
class Config:
|
||||
fields = {"id_": "id"}
|
||||
anystr_strip_whitespace = True
|
||||
alias_generator = to_camel
|
||||
json_encoders = {datetime: lambda v: v.strftime("%d-%b-%Y %H:%M")}
|
||||
|
||||
|
||||
class DeviceLink(BaseModel):
|
||||
|
||||
@@ -4,7 +4,9 @@ import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
import { environment } from '../../environments/environment';
|
||||
import { Device } from '../core/device';
|
||||
import { User } from '../core/user';
|
||||
import { CookieService } from '../shared/cookie.service';
|
||||
|
||||
const loginUrl = '/token';
|
||||
const refreshUrl = '/refresh';
|
||||
@@ -14,10 +16,14 @@ const JWT_USER = 'JWT_USER';
|
||||
export class AuthService {
|
||||
private currentUserSubject: BehaviorSubject<User>;
|
||||
public currentUser: Observable<User>;
|
||||
public device: Device;
|
||||
|
||||
constructor(private http: HttpClient) {
|
||||
constructor(private http: HttpClient, private cs: CookieService) {
|
||||
this.checkStorage();
|
||||
this.currentUser = this.currentUserSubject.asObservable();
|
||||
const deviceId = this.cs.getCookie('device_id');
|
||||
const device = this.cs.getCookie('device');
|
||||
this.device = new Device({ id: deviceId, name: device });
|
||||
}
|
||||
|
||||
static parseJwt(token): User {
|
||||
|
||||
@@ -3,5 +3,13 @@ import { Section } from './section';
|
||||
export class Device {
|
||||
id: string;
|
||||
name: string;
|
||||
enabled: boolean;
|
||||
section: Section;
|
||||
creationDate: string;
|
||||
lastUser: string;
|
||||
lastDate?: string;
|
||||
|
||||
public constructor(init?: Partial<Device>) {
|
||||
Object.assign(this, init);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ export class User {
|
||||
access_token?: string;
|
||||
exp?: number;
|
||||
ver: string;
|
||||
lastDevice: string;
|
||||
lastDate?: string;
|
||||
|
||||
public constructor(init?: Partial<User>) {
|
||||
Object.assign(this, init);
|
||||
|
||||
@@ -39,6 +39,9 @@
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div fxLayout="row">
|
||||
<mat-checkbox formControlName="enabled">Enabled?</mat-checkbox>
|
||||
</div>
|
||||
</form>
|
||||
</mat-card-content>
|
||||
<mat-card-actions>
|
||||
@@ -47,5 +50,8 @@
|
||||
Delete
|
||||
</button>
|
||||
</mat-card-actions>
|
||||
<mat-card-subtitle>
|
||||
Created on <strong>{{ item.creationDate | localTime }}</strong>
|
||||
</mat-card-subtitle>
|
||||
</mat-card>
|
||||
</div>
|
||||
|
||||
@@ -35,6 +35,7 @@ export class DeviceDetailComponent implements OnInit, AfterViewInit {
|
||||
this.form = this.fb.group({
|
||||
name: '',
|
||||
section: '',
|
||||
enabled: '',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -50,6 +51,7 @@ export class DeviceDetailComponent implements OnInit, AfterViewInit {
|
||||
this.form.setValue({
|
||||
name: this.item.name || '',
|
||||
section: this.item.section.id ? this.item.section.id : '',
|
||||
enabled: this.item.enabled,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -100,6 +102,7 @@ export class DeviceDetailComponent implements OnInit, AfterViewInit {
|
||||
const formModel = this.form.value;
|
||||
this.item.name = formModel.name;
|
||||
this.item.section.id = formModel.section;
|
||||
this.item.enabled = formModel.enabled;
|
||||
return this.item;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,11 +17,31 @@
|
||||
</ng-container>
|
||||
|
||||
<!-- Section Column -->
|
||||
<ng-container matColumnDef="tax">
|
||||
<ng-container matColumnDef="section">
|
||||
<mat-header-cell *matHeaderCellDef>Section</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row">{{ row.section.name }}</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Section Column -->
|
||||
<ng-container matColumnDef="enabled">
|
||||
<mat-header-cell *matHeaderCellDef>Enabled</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row">{{ row.enabled }}</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Creation Date Column -->
|
||||
<ng-container matColumnDef="creationDate">
|
||||
<mat-header-cell *matHeaderCellDef>Created</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row">{{ row.creationDate | localTime }}</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Last Login Column -->
|
||||
<ng-container matColumnDef="last">
|
||||
<mat-header-cell *matHeaderCellDef>Last Login</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row"
|
||||
>{{ row.lastUser }} @ {{ row.lastDate ? (row.lastDate | localTime) : 'Never' }}</mat-cell
|
||||
>
|
||||
</ng-container>
|
||||
|
||||
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
|
||||
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
|
||||
</mat-table>
|
||||
|
||||
@@ -14,7 +14,7 @@ export class DeviceListComponent implements OnInit {
|
||||
dataSource: DeviceListDataSource;
|
||||
list: Device[];
|
||||
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
|
||||
displayedColumns = ['name'];
|
||||
displayedColumns = ['name', 'section', 'enabled', 'creationDate', 'last'];
|
||||
|
||||
constructor(private route: ActivatedRoute) {}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs/internal/Observable';
|
||||
import { catchError } from 'rxjs/operators';
|
||||
@@ -6,10 +6,7 @@ import { catchError } from 'rxjs/operators';
|
||||
import { Device } from '../core/device';
|
||||
import { ErrorLoggerService } from '../core/error-logger.service';
|
||||
|
||||
const httpOptions = {
|
||||
headers: new HttpHeaders({ 'Content-Type': 'application/json' }),
|
||||
};
|
||||
const url = '/v1/devices';
|
||||
const url = '/api/devices';
|
||||
const serviceName = 'DeviceService';
|
||||
|
||||
@Injectable({
|
||||
@@ -19,7 +16,7 @@ export class DeviceService {
|
||||
constructor(private http: HttpClient, private log: ErrorLoggerService) {}
|
||||
|
||||
get(id: string): Observable<Device> {
|
||||
const getUrl: string = id === null ? `${url}/new` : `${url}/${id}`;
|
||||
const getUrl: string = id === null ? `${url}` : `${url}/${id}`;
|
||||
return <Observable<Device>>(
|
||||
this.http
|
||||
.get<Device>(getUrl)
|
||||
@@ -28,10 +25,9 @@ export class DeviceService {
|
||||
}
|
||||
|
||||
list(): Observable<Device[]> {
|
||||
const options = { params: new HttpParams().set('l', '') };
|
||||
return <Observable<Device[]>>(
|
||||
this.http
|
||||
.get<Device[]>(url, options)
|
||||
.get<Device[]>(`${url}/list`)
|
||||
.pipe(catchError(this.log.handleError(serviceName, 'list')))
|
||||
);
|
||||
}
|
||||
@@ -39,7 +35,7 @@ export class DeviceService {
|
||||
save(device: Device): Observable<Device> {
|
||||
return <Observable<Device>>(
|
||||
this.http
|
||||
.post<Device>(`${url}/new`, device, httpOptions)
|
||||
.post<Device>(`${url}`, device)
|
||||
.pipe(catchError(this.log.handleError(serviceName, 'save')))
|
||||
);
|
||||
}
|
||||
@@ -47,7 +43,7 @@ export class DeviceService {
|
||||
update(device: Device): Observable<Device> {
|
||||
return <Observable<Device>>(
|
||||
this.http
|
||||
.put<Device>(`${url}/${device.id}`, device, httpOptions)
|
||||
.put<Device>(`${url}/${device.id}`, device)
|
||||
.pipe(catchError(this.log.handleError(serviceName, 'update')))
|
||||
);
|
||||
}
|
||||
@@ -62,7 +58,7 @@ export class DeviceService {
|
||||
delete(id: string): Observable<Device> {
|
||||
return <Observable<Device>>(
|
||||
this.http
|
||||
.delete<Device>(`${url}/${id}`, httpOptions)
|
||||
.delete<Device>(`${url}/${id}`)
|
||||
.pipe(catchError(this.log.handleError(serviceName, 'delete')))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { FlexLayoutModule } from '@angular/flex-layout';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
import { MatOptionModule } from '@angular/material/core';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
@@ -12,6 +13,8 @@ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
|
||||
import { SharedModule } from '../shared/shared.module';
|
||||
|
||||
import { DeviceDetailComponent } from './device-detail/device-detail.component';
|
||||
import { DeviceListComponent } from './device-list/device-list.component';
|
||||
import { DevicesRoutingModule } from './devices-routing.module';
|
||||
@@ -31,6 +34,8 @@ import { DevicesRoutingModule } from './devices-routing.module';
|
||||
MatTableModule,
|
||||
ReactiveFormsModule,
|
||||
DevicesRoutingModule,
|
||||
MatCheckboxModule,
|
||||
SharedModule,
|
||||
],
|
||||
declarations: [DeviceListComponent, DeviceDetailComponent],
|
||||
})
|
||||
|
||||
@@ -199,5 +199,5 @@
|
||||
</mat-card>
|
||||
</div>
|
||||
<footer class="footer">
|
||||
<p>Backend: v{{ auth.user?.ver }} / Frontend: v{{ version }}</p>
|
||||
<p>Backend: v{{ auth.user?.ver }} / Frontend: v{{ version }} on {{ auth.device.name }}</p>
|
||||
</footer>
|
||||
|
||||
@@ -32,6 +32,15 @@
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Last Login Column -->
|
||||
<ng-container matColumnDef="last">
|
||||
<mat-header-cell *matHeaderCellDef>Last Login</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row"
|
||||
>{{ row.lastDevice }} @
|
||||
{{ row.lastDate ? (row.lastDate | localTime) : 'Never' }}</mat-cell
|
||||
>
|
||||
</ng-container>
|
||||
|
||||
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
|
||||
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
|
||||
</mat-table>
|
||||
|
||||
@@ -14,7 +14,7 @@ export class UserListComponent implements OnInit {
|
||||
dataSource: UserListDataSource;
|
||||
list: User[];
|
||||
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
|
||||
displayedColumns = ['name', 'lockedOut', 'roles'];
|
||||
displayedColumns = ['name', 'lockedOut', 'roles', 'last'];
|
||||
|
||||
constructor(private route: ActivatedRoute) {}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user