mirror of
https://github.com/D4M13N-D3V/comissions-app-core-api.git
synced 2025-03-13 01:24:54 +00:00
Initial Files
This commit is contained in:
commit
003bb0413c
11
GitVersion.yml
Normal file
11
GitVersion.yml
Normal file
@ -0,0 +1,11 @@
|
||||
assembly-versioning-scheme: MajorMinorPatch
|
||||
mode: ContinuousDelivery
|
||||
branches: {}
|
||||
ignore:
|
||||
sha: []
|
||||
merge-message-formats: {}
|
||||
commit-message-incrementing: Enabled
|
||||
major-version-bump-message: "^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(\\([\\w\\s-]*\\))?(!:|:.*\\n\\n((.+\\n)+\\n)?BREAKING CHANGE:\\s.+)"
|
||||
minor-version-bump-message: "^(feat)(\\([\\w\\s-]*\\))?:"
|
||||
patch-version-bump-message: "^(build|chore|ci|docs|fix|perf|refactor|revert|style|test)(\\([\\w\\s-]*\\))?:"
|
||||
|
71
README.md
Normal file
71
README.md
Normal file
@ -0,0 +1,71 @@
|
||||
# Comissions.app
|
||||
|
||||
## Description
|
||||
|
||||
This is a application that provides a platform to allow creatives to sell their services without intense moderation.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Project Name](#project-name)
|
||||
- [Description](#description)
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Prerequisites](#prerequisites)
|
||||
- [Getting Started](#getting-started)
|
||||
- [Clone the Repository](#clone-the-repository)
|
||||
- [Build and Run with Docker](#build-and-run-with-docker)
|
||||
- [Usage](#usage)
|
||||
- [Swagger UI](#swagger-ui)
|
||||
- [Contributing](#contributing)
|
||||
- [License](#license)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- [.NET 8 SDK](https://dotnet.microsoft.com/download)
|
||||
- [Docker](https://www.docker.com/get-started)
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Clone the Repository
|
||||
|
||||
```bash
|
||||
git clone https://github.com/D4M13N-D3V/art_platform
|
||||
cd art_platform
|
||||
```
|
||||
|
||||
### Build and Run with Docker
|
||||
|
||||
Build the Docker image:
|
||||
|
||||
```bash
|
||||
docker build -t art-platform -f ./src/ArtPlatform.API/Dockerfile --force-rm .
|
||||
```
|
||||
|
||||
Run the Docker container:
|
||||
|
||||
```bash
|
||||
docker run -p 8080:80 art-platform
|
||||
```
|
||||
|
||||
The API should be accessible at `http://localhost:8080`.
|
||||
|
||||
## Usage
|
||||
|
||||
Describe how to use your API and any specific details or considerations that users need to be aware of.
|
||||
|
||||
## Swagger UI
|
||||
|
||||
The API is documented using Swagger UI. Once the application is running, you can access the Swagger UI at:
|
||||
|
||||
```plaintext
|
||||
http://localhost:8080/swagger
|
||||
```
|
||||
|
||||
This provides an interactive interface for testing and exploring your API endpoints.
|
||||
|
||||
## Contributing
|
||||
|
||||
If you would like to contribute to the project, please follow the guidelines in [CONTRIBUTING.md](CONTRIBUTING.md).
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the [License Name] - see the [LICENSE.md](LICENSE.md) file for details.
|
59
docs/architecture_diagram.drawio
Normal file
59
docs/architecture_diagram.drawio
Normal file
@ -0,0 +1,59 @@
|
||||
<mxfile host="Electron" modified="2024-01-29T05:30:57.240Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/22.1.2 Chrome/114.0.5735.289 Electron/25.9.4 Safari/537.36" etag="hqyKwuYn-BmlLsgfQ51i" version="22.1.2" type="device">
|
||||
<diagram name="Page-1" id="JpjQ_aS7q1FhBQwQmMJn">
|
||||
<mxGraphModel dx="1434" dy="838" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="RHmSW2tqYuRQQK1HVGpt-1" value="comissions.app" style="swimlane;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="70" y="210" width="270" height="220" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="RHmSW2tqYuRQQK1HVGpt-2" value="API" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="RHmSW2tqYuRQQK1HVGpt-1">
|
||||
<mxGeometry x="131" y="80" width="120" height="20" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="RHmSW2tqYuRQQK1HVGpt-3" value=".NET 8 ASP.NET" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="RHmSW2tqYuRQQK1HVGpt-1">
|
||||
<mxGeometry x="130" y="100" width="120" height="20" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="RHmSW2tqYuRQQK1HVGpt-4" value="UI" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="RHmSW2tqYuRQQK1HVGpt-1">
|
||||
<mxGeometry x="131" y="140" width="120" height="20" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="RHmSW2tqYuRQQK1HVGpt-5" value="React NextJS" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="RHmSW2tqYuRQQK1HVGpt-1">
|
||||
<mxGeometry x="130" y="160" width="120" height="20" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="RHmSW2tqYuRQQK1HVGpt-6" value="NPGSQL" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;" vertex="1" parent="RHmSW2tqYuRQQK1HVGpt-1">
|
||||
<mxGeometry x="13" y="58" width="60" height="80" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="RHmSW2tqYuRQQK1HVGpt-7" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.25;exitDx=0;exitDy=0;entryX=1;entryY=0;entryDx=0;entryDy=27.5;entryPerimeter=0;startArrow=classic;startFill=1;" edge="1" parent="RHmSW2tqYuRQQK1HVGpt-1" source="RHmSW2tqYuRQQK1HVGpt-3" target="RHmSW2tqYuRQQK1HVGpt-6">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="RHmSW2tqYuRQQK1HVGpt-8" value="Auth0" style="ellipse;shape=cloud;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="383" y="220" width="75" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="RHmSW2tqYuRQQK1HVGpt-9" value="Novu" style="ellipse;shape=cloud;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="383" y="292" width="75" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="RHmSW2tqYuRQQK1HVGpt-10" value="Stripe" style="ellipse;shape=cloud;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="383" y="360" width="75" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="RHmSW2tqYuRQQK1HVGpt-11" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0.16;entryY=0.55;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="RHmSW2tqYuRQQK1HVGpt-3" target="RHmSW2tqYuRQQK1HVGpt-8">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="360" y="320" />
|
||||
<mxPoint x="360" y="248" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="RHmSW2tqYuRQQK1HVGpt-12" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0.16;entryY=0.55;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="RHmSW2tqYuRQQK1HVGpt-3" target="RHmSW2tqYuRQQK1HVGpt-9">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="RHmSW2tqYuRQQK1HVGpt-13" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0.16;entryY=0.55;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="RHmSW2tqYuRQQK1HVGpt-3" target="RHmSW2tqYuRQQK1HVGpt-10">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="360" y="320" />
|
||||
<mxPoint x="360" y="388" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
BIN
docs/architecture_diagram.drawio.png
Normal file
BIN
docs/architecture_diagram.drawio.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 85 KiB |
326
docs/database_design.drawio
Normal file
326
docs/database_design.drawio
Normal file
@ -0,0 +1,326 @@
|
||||
<mxfile host="Electron" modified="2024-01-29T05:08:53.410Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/22.1.2 Chrome/114.0.5735.289 Electron/25.9.4 Safari/537.36" etag="D43PAxJE1Ifgl-ociygT" version="22.1.2" type="device">
|
||||
<diagram name="Page-1" id="EOcqesTEYwX42nReKtH7">
|
||||
<mxGraphModel dx="1434" dy="838" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-1" value="<h1>Database Design</h1>" style="text;html=1;strokeColor=none;fillColor=none;spacing=5;spacingTop=-20;whiteSpace=wrap;overflow=hidden;rounded=0;align=center;" parent="1" vertex="1">
|
||||
<mxGeometry x="355" y="160" width="850" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-2" value="SellerProfilePortfolioPiece" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="850" y="880" width="190" height="150" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-3" value="PK Id:int" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-2" vertex="1">
|
||||
<mxGeometry y="30" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-5" value="FK SellerServiceId:int&nbsp; &nbsp;nullable" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-2" vertex="1">
|
||||
<mxGeometry y="60" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-4" value="FK SellerProfileId:int" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-2" vertex="1">
|
||||
<mxGeometry y="90" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-11" value="FileReference:string" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-2" vertex="1">
|
||||
<mxGeometry y="120" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-12" value="SellerProfileRequest" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="300" y="80" width="140" height="180" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-13" value="PK Id:int" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-12" vertex="1">
|
||||
<mxGeometry y="30" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-14" value="FK UserId:string" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-12" vertex="1">
|
||||
<mxGeometry y="60" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-15" value="RequestDate:date" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-12" vertex="1">
|
||||
<mxGeometry y="90" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-16" value="AcceptedDate:date" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-12" vertex="1">
|
||||
<mxGeometry y="120" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-17" value="Accepted:bool" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-12" vertex="1">
|
||||
<mxGeometry y="150" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-25" value="SellerServiceOrder" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="820" y="380" width="210" height="300" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-26" value="PK Id:int" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-25" vertex="1">
|
||||
<mxGeometry y="30" width="210" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-27" value="FK BuyerId:string" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-25" vertex="1">
|
||||
<mxGeometry y="60" width="210" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-28" value="FK SellerServiceId:int" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-25" vertex="1">
|
||||
<mxGeometry y="90" width="210" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-29" value="FK SellerId:int" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-25" vertex="1">
|
||||
<mxGeometry y="120" width="210" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-30" value="Status:int" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-25" vertex="1">
|
||||
<mxGeometry y="150" width="210" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-31" value="Price:double" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-25" vertex="1">
|
||||
<mxGeometry y="180" width="210" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-32" value="CreatedDate:date" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-25" vertex="1">
|
||||
<mxGeometry y="210" width="210" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-33" value="TermsAcceptedDate:date&nbsp; &nbsp;nullable" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-25" vertex="1">
|
||||
<mxGeometry y="240" width="210" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-34" value="EndDate:date&nbsp; &nbsp;nullable" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-25" vertex="1">
|
||||
<mxGeometry y="270" width="210" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-35" value="SellerServiceOrderMessage" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="1130" y="110" width="190" height="180" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-36" value="PK Id:int" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-35" vertex="1">
|
||||
<mxGeometry y="30" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-38" value="FK SenderId:string" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-35" vertex="1">
|
||||
<mxGeometry y="60" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-37" value="FK SellerServiceOrderId:int" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-35" vertex="1">
|
||||
<mxGeometry y="90" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-39" value="Message:string" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-35" vertex="1">
|
||||
<mxGeometry y="120" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-40" value="SentAt:date" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-35" vertex="1">
|
||||
<mxGeometry y="150" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-41" value="SellerServiceOrderMessageAttachment" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="1380" y="80" width="221" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-42" value="PK Id:int" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-41" vertex="1">
|
||||
<mxGeometry y="30" width="221" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-43" value="FK SellerServiceOrderMessageId:int" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-41" vertex="1">
|
||||
<mxGeometry y="60" width="221" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-44" value="FileReference:string" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-41" vertex="1">
|
||||
<mxGeometry y="90" width="221" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-55" value="SellerServiceOrderReview" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="1130" y="320" width="190" height="240" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-56" value="PK Id:int" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-55" vertex="1">
|
||||
<mxGeometry y="30" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-59" value="FK Reviwer:string&nbsp;" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-55" vertex="1">
|
||||
<mxGeometry y="60" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-57" value="FK SellerServiceOrderId:int" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-55" vertex="1">
|
||||
<mxGeometry y="90" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-58" value="FK&nbsp;SellerServiceId:int" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-55" vertex="1">
|
||||
<mxGeometry y="120" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="yIItKk7yf84a2ZR0tYBl-34" value="ReviewDate:date" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="UY2qzOe5k0s0eoKJkEdN-55">
|
||||
<mxGeometry y="150" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-60" value="Review:string&nbsp; &nbsp;nullable" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-55" vertex="1">
|
||||
<mxGeometry y="180" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-61" value="Rating:int" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-55" vertex="1">
|
||||
<mxGeometry y="210" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-62" value="User" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="30" y="270" width="210" height="480" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-63" value="PK Id:string" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-62" vertex="1">
|
||||
<mxGeometry y="30" width="210" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-64" value="FK UserSellerProfileId:int&nbsp; &nbsp;nullable" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-62" vertex="1">
|
||||
<mxGeometry y="60" width="210" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-65" value="DisplayName:string" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-62" vertex="1">
|
||||
<mxGeometry y="90" width="210" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-67" value="Biography:string" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-62" vertex="1">
|
||||
<mxGeometry y="120" width="210" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-68" value="Email:string" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-62" vertex="1">
|
||||
<mxGeometry y="150" width="210" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-69" value="Banned:bool" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-62" vertex="1">
|
||||
<mxGeometry y="180" width="210" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-70" value="BannedDate:date&nbsp; &nbsp;nullable" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-62" vertex="1">
|
||||
<mxGeometry y="210" width="210" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-71" value="UnbanDate:date&nbsp; &nbsp;nullable" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-62" vertex="1">
|
||||
<mxGeometry y="240" width="210" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-72" value="BanReason:string&nbsp; &nbsp;nullable" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-62" vertex="1">
|
||||
<mxGeometry y="270" width="210" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-73" value="BanAdminId:string&nbsp; &nbsp;nullable" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-62" vertex="1">
|
||||
<mxGeometry y="300" width="210" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="yIItKk7yf84a2ZR0tYBl-2" value="Suspended:bool" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="UY2qzOe5k0s0eoKJkEdN-62">
|
||||
<mxGeometry y="330" width="210" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="yIItKk7yf84a2ZR0tYBl-3" value="SuspendedDate:date&nbsp; &nbsp;nullable" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="UY2qzOe5k0s0eoKJkEdN-62">
|
||||
<mxGeometry y="360" width="210" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="yIItKk7yf84a2ZR0tYBl-4" value="UnsuspendDate:date&nbsp; &nbsp;nullable" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="UY2qzOe5k0s0eoKJkEdN-62">
|
||||
<mxGeometry y="390" width="210" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="yIItKk7yf84a2ZR0tYBl-5" value="SuspendReason:string&nbsp; &nbsp;nullable" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="UY2qzOe5k0s0eoKJkEdN-62">
|
||||
<mxGeometry y="420" width="210" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="yIItKk7yf84a2ZR0tYBl-1" value="SuspendAdminId:string&nbsp; &nbsp;nullable" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="UY2qzOe5k0s0eoKJkEdN-62">
|
||||
<mxGeometry y="450" width="210" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="yIItKk7yf84a2ZR0tYBl-6" value="UserSellerProfile" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="355" y="690" width="175" height="390" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="yIItKk7yf84a2ZR0tYBl-7" value="PK Id:int" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="yIItKk7yf84a2ZR0tYBl-6">
|
||||
<mxGeometry y="30" width="175" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="yIItKk7yf84a2ZR0tYBl-8" value="FK UserId:string" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="yIItKk7yf84a2ZR0tYBl-6">
|
||||
<mxGeometry y="60" width="175" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="yIItKk7yf84a2ZR0tYBl-9" value="Biography:string" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="yIItKk7yf84a2ZR0tYBl-6">
|
||||
<mxGeometry y="90" width="175" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="yIItKk7yf84a2ZR0tYBl-10" value="SocialMediaLinks:List&lt;string&gt;" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="yIItKk7yf84a2ZR0tYBl-6">
|
||||
<mxGeometry y="120" width="175" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="yIItKk7yf84a2ZR0tYBl-11" value="AgeRestricted:bool" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="yIItKk7yf84a2ZR0tYBl-6">
|
||||
<mxGeometry y="150" width="175" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="yIItKk7yf84a2ZR0tYBl-12" value="PrepaymentRequired:bool" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="yIItKk7yf84a2ZR0tYBl-6">
|
||||
<mxGeometry y="180" width="175" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="yIItKk7yf84a2ZR0tYBl-14" value="AgeRestricted:bool" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="yIItKk7yf84a2ZR0tYBl-6">
|
||||
<mxGeometry y="210" width="175" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="yIItKk7yf84a2ZR0tYBl-15" value="Suspended:bool" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="yIItKk7yf84a2ZR0tYBl-6">
|
||||
<mxGeometry y="240" width="175" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="yIItKk7yf84a2ZR0tYBl-16" value="SuspendedDate:date&nbsp; &nbsp;nullable" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="yIItKk7yf84a2ZR0tYBl-6">
|
||||
<mxGeometry y="270" width="175" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="yIItKk7yf84a2ZR0tYBl-17" value="UnsuspendDate:date&nbsp; &nbsp;nullable" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="yIItKk7yf84a2ZR0tYBl-6">
|
||||
<mxGeometry y="300" width="175" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="yIItKk7yf84a2ZR0tYBl-18" value="SuspendReason:string&nbsp; &nbsp;nullable" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="yIItKk7yf84a2ZR0tYBl-6">
|
||||
<mxGeometry y="330" width="175" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="yIItKk7yf84a2ZR0tYBl-19" value="SuspendAdminId:string&nbsp; &nbsp;nullable" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="yIItKk7yf84a2ZR0tYBl-6">
|
||||
<mxGeometry y="360" width="175" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="yIItKk7yf84a2ZR0tYBl-24" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="yIItKk7yf84a2ZR0tYBl-7" target="UY2qzOe5k0s0eoKJkEdN-20">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-18" value="SellerService" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="590" y="660" width="190" height="210" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-19" value="PK Id:int" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-18" vertex="1">
|
||||
<mxGeometry y="30" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-20" value="FK SellerProfileId:int" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-18" vertex="1">
|
||||
<mxGeometry y="60" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-21" value="Name:string" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-18" vertex="1">
|
||||
<mxGeometry y="90" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-22" value="Description:string" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-18" vertex="1">
|
||||
<mxGeometry y="120" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-23" value="Price:double" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-18" vertex="1">
|
||||
<mxGeometry y="150" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="UY2qzOe5k0s0eoKJkEdN-24" value="Archived:bool" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="UY2qzOe5k0s0eoKJkEdN-18" vertex="1">
|
||||
<mxGeometry y="180" width="190" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="yIItKk7yf84a2ZR0tYBl-25" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="yIItKk7yf84a2ZR0tYBl-7" target="UY2qzOe5k0s0eoKJkEdN-29">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="560" y="735" />
|
||||
<mxPoint x="560" y="515" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="yIItKk7yf84a2ZR0tYBl-26" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="UY2qzOe5k0s0eoKJkEdN-19" target="UY2qzOe5k0s0eoKJkEdN-28">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="yIItKk7yf84a2ZR0tYBl-29" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="yIItKk7yf84a2ZR0tYBl-7" target="UY2qzOe5k0s0eoKJkEdN-64">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="yIItKk7yf84a2ZR0tYBl-30" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="UY2qzOe5k0s0eoKJkEdN-63" target="yIItKk7yf84a2ZR0tYBl-8">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="270" y="315" />
|
||||
<mxPoint x="270" y="765" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="yIItKk7yf84a2ZR0tYBl-31" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="UY2qzOe5k0s0eoKJkEdN-63" target="UY2qzOe5k0s0eoKJkEdN-27">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="380" y="390" as="targetPoint" />
|
||||
<Array as="points">
|
||||
<mxPoint x="320" y="315" />
|
||||
<mxPoint x="320" y="455" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="yIItKk7yf84a2ZR0tYBl-32" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="UY2qzOe5k0s0eoKJkEdN-19" target="UY2qzOe5k0s0eoKJkEdN-55">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="1070" y="705" />
|
||||
<mxPoint x="1070" y="440" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="yIItKk7yf84a2ZR0tYBl-33" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="UY2qzOe5k0s0eoKJkEdN-26" target="UY2qzOe5k0s0eoKJkEdN-57">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="1090" y="425" />
|
||||
<mxPoint x="1090" y="425" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="yIItKk7yf84a2ZR0tYBl-36" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="UY2qzOe5k0s0eoKJkEdN-63" target="UY2qzOe5k0s0eoKJkEdN-59">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="320" y="315" />
|
||||
<mxPoint x="320" y="360" />
|
||||
<mxPoint x="1050" y="360" />
|
||||
<mxPoint x="1050" y="395" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="yIItKk7yf84a2ZR0tYBl-38" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="UY2qzOe5k0s0eoKJkEdN-63" target="UY2qzOe5k0s0eoKJkEdN-38">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="1050" y="315" />
|
||||
<mxPoint x="1050" y="185" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="yIItKk7yf84a2ZR0tYBl-39" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="UY2qzOe5k0s0eoKJkEdN-26" target="UY2qzOe5k0s0eoKJkEdN-37">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="yIItKk7yf84a2ZR0tYBl-40" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="UY2qzOe5k0s0eoKJkEdN-36" target="UY2qzOe5k0s0eoKJkEdN-43">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="yIItKk7yf84a2ZR0tYBl-41" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="UY2qzOe5k0s0eoKJkEdN-63" target="UY2qzOe5k0s0eoKJkEdN-14">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="yIItKk7yf84a2ZR0tYBl-43" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="UY2qzOe5k0s0eoKJkEdN-20" target="UY2qzOe5k0s0eoKJkEdN-5">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="yIItKk7yf84a2ZR0tYBl-44" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="yIItKk7yf84a2ZR0tYBl-7" target="UY2qzOe5k0s0eoKJkEdN-4">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="560" y="735" />
|
||||
<mxPoint x="560" y="985" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
BIN
docs/database_design.drawio.png
Normal file
BIN
docs/database_design.drawio.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 865 KiB |
221
docs/userflow_design.drawio
Normal file
221
docs/userflow_design.drawio
Normal file
@ -0,0 +1,221 @@
|
||||
<mxfile host="Electron" modified="2024-01-29T05:26:23.308Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/22.1.2 Chrome/114.0.5735.289 Electron/25.9.4 Safari/537.36" etag="8Vd_Z-8mX0rej4oU3sUG" version="22.1.2" type="device">
|
||||
<diagram name="Page-1" id="wG4NdPAZgkJ58mmuEcac">
|
||||
<mxGraphModel dx="2895" dy="698" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-5" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-1" target="k-1lLaBYFCKJAabm89fw-4">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-1" value="User" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="60" y="300" width="30" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-9" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-4" target="k-1lLaBYFCKJAabm89fw-8">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-19" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-4" target="k-1lLaBYFCKJAabm89fw-18">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-4" value="Landing Page" style="whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="140" y="318" width="120" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-11" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-8" target="k-1lLaBYFCKJAabm89fw-10">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-8" value="Discover Artists" style="whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="340" y="318" width="120" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-12" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-10" target="k-1lLaBYFCKJAabm89fw-8">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-14" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-10" target="k-1lLaBYFCKJAabm89fw-13">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-10" value="View Artist" style="whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="340" y="423" width="120" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-15" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-13" target="k-1lLaBYFCKJAabm89fw-10">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="340" y="450" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-24" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-13" target="k-1lLaBYFCKJAabm89fw-23">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-13" value="View Service" style="whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="340" y="528" width="120" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-21" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-18" target="k-1lLaBYFCKJAabm89fw-20">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-22" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-18" target="k-1lLaBYFCKJAabm89fw-8">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="-260" y="70" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-26" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-18" target="k-1lLaBYFCKJAabm89fw-25">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-18" value="Login" style="whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="140" y="423" width="120" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-28" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-20" target="k-1lLaBYFCKJAabm89fw-27">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-20" value="View Orders" style="whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="140" y="528" width="120" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-29" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-23" target="k-1lLaBYFCKJAabm89fw-27">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-23" value="Purchase Service" style="whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="340" y="633" width="120" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-44" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-25" target="k-1lLaBYFCKJAabm89fw-43">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-50" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-25" target="k-1lLaBYFCKJAabm89fw-49">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-52" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-25" target="k-1lLaBYFCKJAabm89fw-51">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-63" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-25" target="k-1lLaBYFCKJAabm89fw-62">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-25" value="View Seller Dashboard" style="whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="-447" y="423" width="140" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-31" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-27" target="k-1lLaBYFCKJAabm89fw-30">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-34" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-27" target="k-1lLaBYFCKJAabm89fw-33">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-36" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-27" target="k-1lLaBYFCKJAabm89fw-35">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-38" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-27" target="k-1lLaBYFCKJAabm89fw-37">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-41" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-27" target="k-1lLaBYFCKJAabm89fw-40">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-42" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-27" target="k-1lLaBYFCKJAabm89fw-39">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-84" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-27" target="k-1lLaBYFCKJAabm89fw-83">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-27" value="View Order" style="whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="140" y="633" width="120" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-71" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;dashed=1;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-30" target="k-1lLaBYFCKJAabm89fw-70">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-30" value="Send Message To Seller" style="whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="121" y="721" width="160" height="32" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-33" value="Cancel Order" style="whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="-60" y="630" width="120" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-35" value="Accept Revision" style="whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="-60" y="660" width="120" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-37" value="Pay For Order" style="whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="-60" y="600" width="120" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-39" value="Accept Order Terms" style="whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="-60" y="570" width="120" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-40" value="Deny Revision" style="whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="-60" y="691" width="120" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-43" value="Manage Payout Settings" style="whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="-341" y="317.5" width="140" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-49" value="View Balance &amp; Payout Date" style="whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="-569" y="318" width="164" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-54" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-51" target="k-1lLaBYFCKJAabm89fw-53">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-51" value="View Services" style="whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="-667" y="423" width="140" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-58" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-53" target="k-1lLaBYFCKJAabm89fw-57">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-61" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-53" target="k-1lLaBYFCKJAabm89fw-60">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-53" value="View Service" style="whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="-667" y="519" width="140" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-57" value="Delete Service" style="whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="-667" y="627" width="140" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-60" value="Edit Service Details<br>(price,name,description)" style="whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="-918" y="510" width="140" height="43" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-65" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-62" target="k-1lLaBYFCKJAabm89fw-64">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-62" value="View Orders" style="whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="-447" y="528" width="140" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-67" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-64" target="k-1lLaBYFCKJAabm89fw-66">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-78" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-64" target="k-1lLaBYFCKJAabm89fw-76">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-79" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-64" target="k-1lLaBYFCKJAabm89fw-75">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-80" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-64" target="k-1lLaBYFCKJAabm89fw-73">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-81" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-64" target="k-1lLaBYFCKJAabm89fw-74">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-82" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-64" target="k-1lLaBYFCKJAabm89fw-77">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-64" value="View Order" style="whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="-447" y="630" width="140" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-69" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;dashed=1;" edge="1" parent="1" source="k-1lLaBYFCKJAabm89fw-66" target="k-1lLaBYFCKJAabm89fw-68">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-66" value="Send Message To Buyer" style="whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="-447" y="721" width="140" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-68" value="Upload Attachment" style="whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="-447" y="814" width="140" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-70" value="Upload Attachment" style="whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="130" y="814" width="140" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-73" value="Adjust Price" style="whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="-200" y="629.5" width="120" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-74" value="Complete Revision" style="whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="-200" y="659.5" width="120" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-75" value="Start Order" style="whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="-200" y="599.5" width="120" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-76" value="Accept Order" style="whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="-200" y="569.5" width="120" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-77" value="Cancel Order" style="whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="-200" y="690.5" width="120" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="k-1lLaBYFCKJAabm89fw-83" value="Leave Review" style="whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
|
||||
<mxGeometry x="-60" y="722.5" width="120" height="25" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
BIN
docs/userflow_design.drawio.png
Normal file
BIN
docs/userflow_design.drawio.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 379 KiB |
25
src/.dockerignore
Normal file
25
src/.dockerignore
Normal file
@ -0,0 +1,25 @@
|
||||
**/.dockerignore
|
||||
**/.env
|
||||
**/.git
|
||||
**/.gitignore
|
||||
**/.project
|
||||
**/.settings
|
||||
**/.toolstarget
|
||||
**/.vs
|
||||
**/.vscode
|
||||
**/.idea
|
||||
**/*.*proj.user
|
||||
**/*.dbmdl
|
||||
**/*.jfm
|
||||
**/azds.yaml
|
||||
**/bin
|
||||
**/charts
|
||||
**/docker-compose*
|
||||
**/Dockerfile*
|
||||
**/node_modules
|
||||
**/npm-debug.log
|
||||
**/obj
|
||||
**/secrets.dev.yaml
|
||||
**/values.dev.yaml
|
||||
LICENSE
|
||||
README.md
|
370
src/.idea/.idea.ArtPlatform.Database/.idea/workspace.xml
generated
Normal file
370
src/.idea/.idea.ArtPlatform.Database/.idea/workspace.xml
generated
Normal file
@ -0,0 +1,370 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="AutoGeneratedRunConfigurationManager">
|
||||
<projectFile profileName="http">ArtPlatform.API/ArtPlatform.API.csproj</projectFile>
|
||||
<projectFile profileName="https">ArtPlatform.API/ArtPlatform.API.csproj</projectFile>
|
||||
<projectFile profileName="http">ArtPlatform.App/ArtPlatform.App.csproj</projectFile>
|
||||
<projectFile profileName="https">ArtPlatform.App/ArtPlatform.App.csproj</projectFile>
|
||||
<projectFile>ArtPlatform.Database.Migrator/ArtPlatform.Database.Migrator.csproj</projectFile>
|
||||
<projectFile profileName="https">ArtPlatform.UI/ArtPlatform.UI.csproj</projectFile>
|
||||
<projectFile profileName="http">ArtPlatform.WebApp/ArtPlatform.WebApp.csproj</projectFile>
|
||||
<projectFile profileName="https">ArtPlatform.WebApp/ArtPlatform.WebApp.csproj</projectFile>
|
||||
<projectFile profileName="http">ArtPlatform.WebApplication/ArtPlatform.WebApplication.csproj</projectFile>
|
||||
<projectFile profileName="https">ArtPlatform.WebApplication/ArtPlatform.WebApplication.csproj</projectFile>
|
||||
<projectFile profileName="http">ArtPlatform/ArtPlatform.csproj</projectFile>
|
||||
<projectFile profileName="https">ArtPlatform/ArtPlatform.csproj</projectFile>
|
||||
</component>
|
||||
<component name="AutoImportSettings">
|
||||
<option name="autoReloadType" value="SELECTIVE" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="e251c08f-6fd2-4319-a6ec-5f03319157f3" name="Changes" comment="">
|
||||
<change afterPath="$PROJECT_DIR$/.dockerignore" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/.idea/.idea.ArtPlatform.Database/.idea/workspace.xml" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/ArtPlatform.Database/ApplicationDatabaseConfigurationModel.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/ArtPlatform.Database/ApplicationDbContext.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/ArtPlatform.Database/ArtPlatform.Database.csproj" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/ArtPlatform.Database/Entities/SellerConfiguredSetting.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/ArtPlatform.Database/Entities/SellerProfilePortfolioPiece.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/ArtPlatform.Database/Entities/SellerService.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/ArtPlatform.Database/Entities/SellerServiceOrder.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/ArtPlatform.Database/Entities/SellerServiceOrderMessage.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/ArtPlatform.Database/Entities/SellerServiceOrderMessageAttachment.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/ArtPlatform.Database/Entities/SellerServiceOrderReview.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/ArtPlatform.Database/Entities/SellerSetting.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/ArtPlatform.Database/Entities/User.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/ArtPlatform.Database/Entities/UserSellerProfile.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/ArtPlatform.Database/Enums/EnumOrderStatus.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/ArtPlatform.sln" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../ArtPlatform/.dockerignore" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../ArtPlatform/.idea/.idea.ArtPlatform/.idea/.gitignore" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../ArtPlatform/.idea/.idea.ArtPlatform/.idea/aws.xml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../ArtPlatform/.idea/.idea.ArtPlatform/.idea/encodings.xml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../ArtPlatform/.idea/.idea.ArtPlatform/.idea/indexLayout.xml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../ArtPlatform/.idea/.idea.ArtPlatform/.idea/vcs.xml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../ArtPlatform/ArtPlaform.DAL/ArtPlaform.DAL.csproj" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../ArtPlatform/ArtPlaform.DAL/Class1.cs" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../ArtPlatform/ArtPlatform.Api/ArtPlatform.Api.csproj" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../ArtPlatform/ArtPlatform.Api/Controllers/WeatherForecastController.cs" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../ArtPlatform/ArtPlatform.Api/Dockerfile" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../ArtPlatform/ArtPlatform.Api/Program.cs" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../ArtPlatform/ArtPlatform.Api/Properties/launchSettings.json" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../ArtPlatform/ArtPlatform.Api/WeatherForecast.cs" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../ArtPlatform/ArtPlatform.Api/appsettings.Development.json" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../ArtPlatform/ArtPlatform.Api/appsettings.json" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../ArtPlatform/ArtPlatform.DatabaseUpdater/ArtPlatform.DatabaseUpdater.csproj" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../ArtPlatform/ArtPlatform.DatabaseUpdater/Dockerfile" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../ArtPlatform/ArtPlatform.DatabaseUpdater/Program.cs" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../ArtPlatform/ArtPlatform.sln" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../Damien.ArtPlatform/.idea/.idea.Damien.ArtPlatform/.idea/aws.xml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../Damien.ArtPlatform/.idea/.idea.Damien.ArtPlatform/.idea/indexLayout.xml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../Damien.ArtPlatform/.idea/.idea.Damien.ArtPlatform/.idea/projectSettingsUpdater.xml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../Damien.ArtPlatform/.idea/.idea.Damien.ArtPlatform/.idea/vcs.xml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../Damien.ArtPlatform/.idea/.idea.Damien.ArtPlatform/.idea/workspace.xml" beforeDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/.." />
|
||||
</component>
|
||||
<component name="ProjectColorInfo"><![CDATA[{
|
||||
"associatedIndex": 8
|
||||
}]]></component>
|
||||
<component name="ProjectId" id="2bVSVHjAxjbTSogi69zTRZwrMUs" />
|
||||
<component name="ProjectLevelVcsManager">
|
||||
<ConfirmationsSetting value="2" id="Add" />
|
||||
</component>
|
||||
<component name="ProjectViewState">
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent"><![CDATA[{
|
||||
"keyToString": {
|
||||
".NET Launch Settings Profile.ArtPlatform.API: http.executor": "Run",
|
||||
".NET Launch Settings Profile.ArtPlatform.App: http.executor": "Run",
|
||||
".NET Launch Settings Profile.ArtPlatform.WebApp: http.executor": "Run",
|
||||
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"git-widget-placeholder": "main",
|
||||
"last_opened_file_path": "/home/damienostler/Documents/Github Repositories/art_platform/ArtPlatform.Database/ArtPlatform/ArtPlatform.sln",
|
||||
"node.js.detected.package.eslint": "true",
|
||||
"node.js.detected.package.tslint": "true",
|
||||
"node.js.selected.package.eslint": "(autodetect)",
|
||||
"node.js.selected.package.tslint": "(autodetect)",
|
||||
"nodejs_package_manager_path": "npm",
|
||||
"settings.editor.selected.configurable": "preferences.pluginManager",
|
||||
"vue.rearranger.settings.migration": "true"
|
||||
},
|
||||
"keyToStringList": {
|
||||
"DatabaseDriversLRU": [
|
||||
"postgresql"
|
||||
],
|
||||
"rider.external.source.directories": [
|
||||
"/home/damienostler/.config/JetBrains/Rider2023.3/resharper-host/DecompilerCache",
|
||||
"/home/damienostler/.config/JetBrains/Rider2023.3/resharper-host/SourcesCache",
|
||||
"/home/damienostler/.local/share/Symbols/src"
|
||||
]
|
||||
}
|
||||
}]]></component>
|
||||
<component name="RunManager" selected=".NET Launch Settings Profile.ArtPlatform.App: http">
|
||||
<configuration name="ArtPlatform.Database.Migrator" type="DotNetProject" factoryName=".NET Project">
|
||||
<option name="EXE_PATH" value="" />
|
||||
<option name="PROGRAM_PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="" />
|
||||
<option name="PASS_PARENT_ENVS" value="1" />
|
||||
<option name="USE_EXTERNAL_CONSOLE" value="0" />
|
||||
<option name="USE_MONO" value="0" />
|
||||
<option name="RUNTIME_ARGUMENTS" value="" />
|
||||
<option name="PROJECT_PATH" value="$PROJECT_DIR$/ArtPlatform.Database.Migrator/ArtPlatform.Database.Migrator.csproj" />
|
||||
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
|
||||
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
|
||||
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
|
||||
<option name="PROJECT_KIND" value="DotNetCore" />
|
||||
<option name="PROJECT_TFM" value="" />
|
||||
<method v="2">
|
||||
<option name="Build" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration name="ArtPlatform: http" type="LaunchSettings" factoryName=".NET Launch Settings Profile">
|
||||
<option name="LAUNCH_PROFILE_PROJECT_FILE_PATH" value="$PROJECT_DIR$/ArtPlatform/ArtPlatform.csproj" />
|
||||
<option name="LAUNCH_PROFILE_TFM" value="net8.0" />
|
||||
<option name="LAUNCH_PROFILE_NAME" value="http" />
|
||||
<option name="USE_EXTERNAL_CONSOLE" value="0" />
|
||||
<option name="USE_MONO" value="0" />
|
||||
<option name="RUNTIME_ARGUMENTS" value="" />
|
||||
<option name="GENERATE_APPLICATIONHOST_CONFIG" value="1" />
|
||||
<option name="SHOW_IIS_EXPRESS_OUTPUT" value="0" />
|
||||
<option name="SEND_DEBUG_REQUEST" value="1" />
|
||||
<option name="ADDITIONAL_IIS_EXPRESS_ARGUMENTS" value="" />
|
||||
<method v="2">
|
||||
<option name="Build" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration name="ArtPlatform: https" type="LaunchSettings" factoryName=".NET Launch Settings Profile">
|
||||
<option name="LAUNCH_PROFILE_PROJECT_FILE_PATH" value="$PROJECT_DIR$/ArtPlatform/ArtPlatform.csproj" />
|
||||
<option name="LAUNCH_PROFILE_TFM" value="net8.0" />
|
||||
<option name="LAUNCH_PROFILE_NAME" value="https" />
|
||||
<option name="USE_EXTERNAL_CONSOLE" value="0" />
|
||||
<option name="USE_MONO" value="0" />
|
||||
<option name="RUNTIME_ARGUMENTS" value="" />
|
||||
<option name="GENERATE_APPLICATIONHOST_CONFIG" value="1" />
|
||||
<option name="SHOW_IIS_EXPRESS_OUTPUT" value="0" />
|
||||
<option name="SEND_DEBUG_REQUEST" value="1" />
|
||||
<option name="ADDITIONAL_IIS_EXPRESS_ARGUMENTS" value="" />
|
||||
<method v="2">
|
||||
<option name="Build" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration name="ArtPlatform.API: https" type="LaunchSettings" factoryName=".NET Launch Settings Profile">
|
||||
<option name="LAUNCH_PROFILE_PROJECT_FILE_PATH" value="$PROJECT_DIR$/ArtPlatform.API/ArtPlatform.API.csproj" />
|
||||
<option name="LAUNCH_PROFILE_TFM" value="net8.0" />
|
||||
<option name="LAUNCH_PROFILE_NAME" value="https" />
|
||||
<option name="USE_EXTERNAL_CONSOLE" value="0" />
|
||||
<option name="USE_MONO" value="0" />
|
||||
<option name="RUNTIME_ARGUMENTS" value="" />
|
||||
<option name="GENERATE_APPLICATIONHOST_CONFIG" value="1" />
|
||||
<option name="SHOW_IIS_EXPRESS_OUTPUT" value="0" />
|
||||
<option name="SEND_DEBUG_REQUEST" value="1" />
|
||||
<option name="ADDITIONAL_IIS_EXPRESS_ARGUMENTS" value="" />
|
||||
<method v="2">
|
||||
<option name="Build" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration name="ArtPlatform.App: http" type="LaunchSettings" factoryName=".NET Launch Settings Profile">
|
||||
<option name="LAUNCH_PROFILE_PROJECT_FILE_PATH" value="$PROJECT_DIR$/ArtPlatform.App/ArtPlatform.App.csproj" />
|
||||
<option name="LAUNCH_PROFILE_TFM" value="net8.0" />
|
||||
<option name="LAUNCH_PROFILE_NAME" value="http" />
|
||||
<option name="USE_EXTERNAL_CONSOLE" value="0" />
|
||||
<option name="USE_MONO" value="0" />
|
||||
<option name="RUNTIME_ARGUMENTS" value="" />
|
||||
<option name="GENERATE_APPLICATIONHOST_CONFIG" value="1" />
|
||||
<option name="SHOW_IIS_EXPRESS_OUTPUT" value="0" />
|
||||
<option name="SEND_DEBUG_REQUEST" value="1" />
|
||||
<option name="ADDITIONAL_IIS_EXPRESS_ARGUMENTS" value="" />
|
||||
<method v="2">
|
||||
<option name="Build" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration name="ArtPlatform.App: https" type="LaunchSettings" factoryName=".NET Launch Settings Profile">
|
||||
<option name="LAUNCH_PROFILE_PROJECT_FILE_PATH" value="$PROJECT_DIR$/ArtPlatform.App/ArtPlatform.App.csproj" />
|
||||
<option name="LAUNCH_PROFILE_TFM" value="net8.0" />
|
||||
<option name="LAUNCH_PROFILE_NAME" value="https" />
|
||||
<option name="USE_EXTERNAL_CONSOLE" value="0" />
|
||||
<option name="USE_MONO" value="0" />
|
||||
<option name="RUNTIME_ARGUMENTS" value="" />
|
||||
<option name="GENERATE_APPLICATIONHOST_CONFIG" value="1" />
|
||||
<option name="SHOW_IIS_EXPRESS_OUTPUT" value="0" />
|
||||
<option name="SEND_DEBUG_REQUEST" value="1" />
|
||||
<option name="ADDITIONAL_IIS_EXPRESS_ARGUMENTS" value="" />
|
||||
<method v="2">
|
||||
<option name="Build" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration name="ArtPlatform.WebApplication: https" type="LaunchSettings" factoryName=".NET Launch Settings Profile">
|
||||
<option name="LAUNCH_PROFILE_PROJECT_FILE_PATH" value="$PROJECT_DIR$/ArtPlatform.WebApplication/ArtPlatform.WebApplication.csproj" />
|
||||
<option name="LAUNCH_PROFILE_TFM" value="net8.0" />
|
||||
<option name="LAUNCH_PROFILE_NAME" value="https" />
|
||||
<option name="USE_EXTERNAL_CONSOLE" value="0" />
|
||||
<option name="USE_MONO" value="0" />
|
||||
<option name="RUNTIME_ARGUMENTS" value="" />
|
||||
<option name="GENERATE_APPLICATIONHOST_CONFIG" value="1" />
|
||||
<option name="SHOW_IIS_EXPRESS_OUTPUT" value="0" />
|
||||
<option name="SEND_DEBUG_REQUEST" value="1" />
|
||||
<option name="ADDITIONAL_IIS_EXPRESS_ARGUMENTS" value="" />
|
||||
<method v="2">
|
||||
<option name="Build" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration name="ArtPlatform.API/Dockerfile" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
|
||||
<deployment type="dockerfile">
|
||||
<settings>
|
||||
<option name="imageTag" value="artplatform.api" />
|
||||
<option name="containerName" value="artplatform.api" />
|
||||
<option name="contextFolderPath" value="$PROJECT_DIR$" />
|
||||
<option name="portBindings">
|
||||
<list>
|
||||
<DockerPortBindingImpl>
|
||||
<option name="containerPort" value="8080" />
|
||||
<option name="hostIp" value="127.0.0.1" />
|
||||
<option name="hostPort" value="8080" />
|
||||
</DockerPortBindingImpl>
|
||||
</list>
|
||||
</option>
|
||||
<option name="sourceFilePath" value="ArtPlatform.API/Dockerfile" />
|
||||
</settings>
|
||||
</deployment>
|
||||
<EXTENSION ID="com.jetbrains.rider.docker.debug" isFastModeEnabled="true" isSslEnabled="false" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="ArtPlatform.App/Dockerfile" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
|
||||
<deployment type="dockerfile">
|
||||
<settings>
|
||||
<option name="imageTag" value="artplatform.app" />
|
||||
<option name="containerName" value="artplatform.app" />
|
||||
<option name="contextFolderPath" value="$PROJECT_DIR$" />
|
||||
<option name="portBindings">
|
||||
<list>
|
||||
<DockerPortBindingImpl>
|
||||
<option name="containerPort" value="8080" />
|
||||
<option name="hostIp" value="127.0.0.1" />
|
||||
<option name="hostPort" value="8080" />
|
||||
</DockerPortBindingImpl>
|
||||
</list>
|
||||
</option>
|
||||
<option name="sourceFilePath" value="ArtPlatform.App/Dockerfile" />
|
||||
</settings>
|
||||
</deployment>
|
||||
<EXTENSION ID="com.jetbrains.rider.docker.debug" isFastModeEnabled="true" isSslEnabled="false" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="ArtPlatform/Dockerfile" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
|
||||
<deployment type="dockerfile">
|
||||
<settings>
|
||||
<option name="imageTag" value="artplatform" />
|
||||
<option name="containerName" value="artplatform" />
|
||||
<option name="contextFolderPath" value="$PROJECT_DIR$" />
|
||||
<option name="portBindings">
|
||||
<list>
|
||||
<DockerPortBindingImpl>
|
||||
<option name="containerPort" value="8080" />
|
||||
<option name="hostIp" value="127.0.0.1" />
|
||||
<option name="hostPort" value="8080" />
|
||||
</DockerPortBindingImpl>
|
||||
</list>
|
||||
</option>
|
||||
<option name="sourceFilePath" value="ArtPlatform/Dockerfile" />
|
||||
</settings>
|
||||
</deployment>
|
||||
<EXTENSION ID="com.jetbrains.rider.docker.debug" isFastModeEnabled="true" isSslEnabled="false" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="ArtPlatform.UI/Dockerfile" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
|
||||
<deployment type="dockerfile">
|
||||
<settings>
|
||||
<option name="imageTag" value="artplatform.ui" />
|
||||
<option name="containerName" value="artplatform.ui" />
|
||||
<option name="contextFolderPath" value="$PROJECT_DIR$" />
|
||||
<option name="portBindings">
|
||||
<list>
|
||||
<DockerPortBindingImpl>
|
||||
<option name="containerPort" value="8080" />
|
||||
<option name="hostIp" value="127.0.0.1" />
|
||||
<option name="hostPort" value="8080" />
|
||||
</DockerPortBindingImpl>
|
||||
</list>
|
||||
</option>
|
||||
<option name="sourceFilePath" value="ArtPlatform.UI/Dockerfile" />
|
||||
</settings>
|
||||
</deployment>
|
||||
<EXTENSION ID="com.jetbrains.rider.docker.debug" isFastModeEnabled="true" isSslEnabled="false" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="ArtPlatform.WebApp/Dockerfile" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
|
||||
<deployment type="dockerfile">
|
||||
<settings>
|
||||
<option name="imageTag" value="artplatform.webapp" />
|
||||
<option name="containerName" value="artplatform.webapp" />
|
||||
<option name="contextFolderPath" value="$PROJECT_DIR$" />
|
||||
<option name="portBindings">
|
||||
<list>
|
||||
<DockerPortBindingImpl>
|
||||
<option name="containerPort" value="8080" />
|
||||
<option name="hostIp" value="127.0.0.1" />
|
||||
<option name="hostPort" value="8080" />
|
||||
</DockerPortBindingImpl>
|
||||
</list>
|
||||
</option>
|
||||
<option name="sourceFilePath" value="ArtPlatform.WebApp/Dockerfile" />
|
||||
</settings>
|
||||
</deployment>
|
||||
<EXTENSION ID="com.jetbrains.rider.docker.debug" isFastModeEnabled="true" isSslEnabled="false" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="ArtPlatform.WebApplication/Dockerfile" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
|
||||
<deployment type="dockerfile">
|
||||
<settings>
|
||||
<option name="imageTag" value="artplatform.webapplication" />
|
||||
<option name="containerName" value="artplatform.webapplication" />
|
||||
<option name="contextFolderPath" value="$PROJECT_DIR$" />
|
||||
<option name="portBindings">
|
||||
<list>
|
||||
<DockerPortBindingImpl>
|
||||
<option name="containerPort" value="8080" />
|
||||
<option name="hostIp" value="127.0.0.1" />
|
||||
<option name="hostPort" value="8080" />
|
||||
</DockerPortBindingImpl>
|
||||
</list>
|
||||
</option>
|
||||
<option name="sourceFilePath" value="ArtPlatform.WebApplication/Dockerfile" />
|
||||
</settings>
|
||||
</deployment>
|
||||
<EXTENSION ID="com.jetbrains.rider.docker.debug" isFastModeEnabled="true" isSslEnabled="false" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration default="true" type="docker-deploy" factoryName="dockerfile" temporary="true">
|
||||
<deployment type="dockerfile" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
||||
<component name="TaskManager">
|
||||
<task active="true" id="Default" summary="Default task">
|
||||
<changelist id="e251c08f-6fd2-4319-a6ec-5f03319157f3" name="Changes" comment="" />
|
||||
<created>1706298775013</created>
|
||||
<option name="number" value="Default" />
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1706298775013</updated>
|
||||
<workItem from="1706298780176" duration="10198000" />
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
<option name="version" value="3" />
|
||||
</component>
|
||||
<component name="VcsManagerConfiguration">
|
||||
<option name="CLEAR_INITIAL_COMMIT_MESSAGE" value="true" />
|
||||
</component>
|
||||
</project>
|
@ -0,0 +1 @@
|
||||
#n:artplatform
|
@ -0,0 +1,2 @@
|
||||
#n:public
|
||||
!<md> [1314, 0, null, null, -2147483648, -2147483648]
|
271
src/.idea/.idea.ArtPlatform/.idea/workspace.xml
generated
Normal file
271
src/.idea/.idea.ArtPlatform/.idea/workspace.xml
generated
Normal file
@ -0,0 +1,271 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="AutoGeneratedRunConfigurationManager">
|
||||
<projectFile profileName="http">ArtPlatform.API/ArtPlatform.API.csproj</projectFile>
|
||||
<projectFile profileName="https">ArtPlatform.API/ArtPlatform.API.csproj</projectFile>
|
||||
<projectFile>ArtPlatform.Database.Migrator/ArtPlatform.Database.Migrator.csproj</projectFile>
|
||||
<projectFile profileName="http">ArtPlatform/ArtPlatform.csproj</projectFile>
|
||||
<projectFile profileName="https">ArtPlatform/ArtPlatform.csproj</projectFile>
|
||||
</component>
|
||||
<component name="AutoImportSettings">
|
||||
<option name="autoReloadType" value="SELECTIVE" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="e251c08f-6fd2-4319-a6ec-5f03319157f3" name="Changes" comment="">
|
||||
<change beforePath="$PROJECT_DIR$/ui/components/header.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/ui/components/header.tsx" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/ui/package-lock.json" beforeDir="false" afterPath="$PROJECT_DIR$/ui/package-lock.json" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/ui/package.json" beforeDir="false" afterPath="$PROJECT_DIR$/ui/package.json" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/ui/pages/_app.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/ui/pages/_app.tsx" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/ui/pages/index.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/ui/pages/index.tsx" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/.." />
|
||||
</component>
|
||||
<component name="HighlightingSettingsPerFile">
|
||||
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/DecompilerCache/decompiler/6fb07e288afa4fb5b6e5c73ac90727b21dea00/d1/1e296c5d/ActionMethodExecutor.cs" root0="SKIP_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/ArtPlatform.API/react/package-lock.json" root0="SKIP_HIGHLIGHTING" />
|
||||
</component>
|
||||
<component name="KubernetesApiProvider">{
|
||||
"contexts": [
|
||||
{
|
||||
"name": "minikube",
|
||||
"originalNamespace": "default"
|
||||
}
|
||||
],
|
||||
"isMigrated": true
|
||||
}</component>
|
||||
<component name="KubernetesSettings">
|
||||
<option name="contextName" value="minikube" />
|
||||
</component>
|
||||
<component name="MarkdownSettingsMigration">
|
||||
<option name="stateVersion" value="1" />
|
||||
</component>
|
||||
<component name="ProjectColorInfo">{
|
||||
"associatedIndex": 8
|
||||
}</component>
|
||||
<component name="ProjectId" id="2bVSVHjAxjbTSogi69zTRZwrMUs" />
|
||||
<component name="ProjectLevelVcsManager">
|
||||
<ConfirmationsSetting value="2" id="Add" />
|
||||
</component>
|
||||
<component name="ProjectViewState">
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent">{
|
||||
"keyToString": {
|
||||
".NET Launch Settings Profile.ArtPlatform.API: https.executor": "Run",
|
||||
".NET Project.ArtPlatform.Database.Migrator.executor": "Run",
|
||||
"Docker.ArtPlatform.API/Dockerfile.executor": "Run",
|
||||
"HTTP Request.All in generated-requests.executor": "Run",
|
||||
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"git-widget-placeholder": "main",
|
||||
"last_opened_file_path": "/home/damienostler/Documents/Github Repositories/art_platform/src/ArtPlatform.Database/ArtPlatform.Database.csproj",
|
||||
"node.js.detected.package.eslint": "true",
|
||||
"node.js.detected.package.tslint": "true",
|
||||
"node.js.selected.package.eslint": "(autodetect)",
|
||||
"node.js.selected.package.tslint": "(autodetect)",
|
||||
"nodejs_package_manager_path": "npm",
|
||||
"settings.editor.selected.configurable": "preferences.pluginManager",
|
||||
"ts.external.directory.path": "/home/damienostler/Documents/Github Repositories/art_platform/src/ArtPlatform.API/react/node_modules/typescript/lib",
|
||||
"vue.rearranger.settings.migration": "true"
|
||||
},
|
||||
"keyToStringList": {
|
||||
"DatabaseDriversLRU": [
|
||||
"postgresql"
|
||||
],
|
||||
"rider.external.source.directories": [
|
||||
"/home/damienostler/.config/JetBrains/Rider2023.3/resharper-host/DecompilerCache",
|
||||
"/home/damienostler/.config/JetBrains/Rider2023.3/resharper-host/SourcesCache",
|
||||
"/home/damienostler/.local/share/Symbols/src"
|
||||
]
|
||||
}
|
||||
}</component>
|
||||
<component name="RunManager" selected=".NET Launch Settings Profile.ArtPlatform.API: https">
|
||||
<configuration name="ArtPlatform.Database.Migrator" type="DotNetProject" factoryName=".NET Project">
|
||||
<option name="EXE_PATH" value="" />
|
||||
<option name="PROGRAM_PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="" />
|
||||
<option name="PASS_PARENT_ENVS" value="1" />
|
||||
<option name="USE_EXTERNAL_CONSOLE" value="0" />
|
||||
<option name="USE_MONO" value="0" />
|
||||
<option name="RUNTIME_ARGUMENTS" value="" />
|
||||
<option name="PROJECT_PATH" value="$PROJECT_DIR$/comissions.app.database.migrator/comissions.app.database.migrator.csproj" />
|
||||
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
|
||||
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
|
||||
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
|
||||
<option name="PROJECT_KIND" value="DotNetCore" />
|
||||
<option name="PROJECT_TFM" value="" />
|
||||
<method v="2">
|
||||
<option name="Build" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration name="All in generated-requests" type="HttpClient.HttpRequestRunConfigurationType" factoryName="HTTP Request" temporary="true" path="$APPLICATION_CONFIG_DIR$/scratches/generated-requests.http">
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="ArtPlatform.API: http" type="LaunchSettings" factoryName=".NET Launch Settings Profile">
|
||||
<option name="LAUNCH_PROFILE_PROJECT_FILE_PATH" value="$PROJECT_DIR$/comissions.app.api/comissions.app.api.csproj" />
|
||||
<option name="LAUNCH_PROFILE_TFM" value="net8.0" />
|
||||
<option name="LAUNCH_PROFILE_NAME" value="http" />
|
||||
<option name="USE_EXTERNAL_CONSOLE" value="0" />
|
||||
<option name="USE_MONO" value="0" />
|
||||
<option name="RUNTIME_ARGUMENTS" value="" />
|
||||
<option name="GENERATE_APPLICATIONHOST_CONFIG" value="1" />
|
||||
<option name="SHOW_IIS_EXPRESS_OUTPUT" value="0" />
|
||||
<option name="SEND_DEBUG_REQUEST" value="1" />
|
||||
<option name="ADDITIONAL_IIS_EXPRESS_ARGUMENTS" value="" />
|
||||
<method v="2">
|
||||
<option name="Build" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration name="ArtPlatform.API: https" type="LaunchSettings" factoryName=".NET Launch Settings Profile">
|
||||
<option name="LAUNCH_PROFILE_PROJECT_FILE_PATH" value="$PROJECT_DIR$/comissions.app.api/comissions.app.api.csproj" />
|
||||
<option name="LAUNCH_PROFILE_TFM" value="net8.0" />
|
||||
<option name="LAUNCH_PROFILE_NAME" value="https" />
|
||||
<option name="USE_EXTERNAL_CONSOLE" value="0" />
|
||||
<option name="USE_MONO" value="0" />
|
||||
<option name="RUNTIME_ARGUMENTS" value="" />
|
||||
<option name="GENERATE_APPLICATIONHOST_CONFIG" value="1" />
|
||||
<option name="SHOW_IIS_EXPRESS_OUTPUT" value="0" />
|
||||
<option name="SEND_DEBUG_REQUEST" value="1" />
|
||||
<option name="ADDITIONAL_IIS_EXPRESS_ARGUMENTS" value="" />
|
||||
<method v="2">
|
||||
<option name="Build" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration default="true" type="docker-deploy" factoryName="dockerfile" temporary="true">
|
||||
<deployment type="dockerfile">
|
||||
<settings />
|
||||
</deployment>
|
||||
<EXTENSION ID="com.jetbrains.rider.docker.debug" isFastModeEnabled="true" isSslEnabled="false" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="comissions.app.api/Dockerfile: Compose Deployment" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
|
||||
<deployment type="dockerfile">
|
||||
<settings>
|
||||
<option name="imageTag" value="artplatform.api" />
|
||||
<option name="containerName" value="artplatform.api" />
|
||||
<option name="contextFolderPath" value="$PROJECT_DIR$" />
|
||||
<option name="portBindings">
|
||||
<list>
|
||||
<DockerPortBindingImpl>
|
||||
<option name="containerPort" value="8080" />
|
||||
<option name="hostIp" value="127.0.0.1" />
|
||||
<option name="hostPort" value="8080" />
|
||||
</DockerPortBindingImpl>
|
||||
</list>
|
||||
</option>
|
||||
<option name="sourceFilePath" value="comissions.app.api/Dockerfile" />
|
||||
</settings>
|
||||
</deployment>
|
||||
<EXTENSION ID="com.jetbrains.rider.docker.debug" isFastModeEnabled="true" isSslEnabled="false" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<recent_temporary>
|
||||
<list>
|
||||
<item itemvalue="HTTP Request.All in generated-requests" />
|
||||
</list>
|
||||
</recent_temporary>
|
||||
</component>
|
||||
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
||||
<component name="TaskManager">
|
||||
<task active="true" id="Default" summary="Default task">
|
||||
<changelist id="e251c08f-6fd2-4319-a6ec-5f03319157f3" name="Changes" comment="" />
|
||||
<created>1706298775013</created>
|
||||
<option name="number" value="Default" />
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1706298775013</updated>
|
||||
<workItem from="1706298780176" duration="5462000" />
|
||||
<workItem from="1706328737604" duration="1191000" />
|
||||
<workItem from="1706329945610" duration="25743000" />
|
||||
<workItem from="1706356001506" duration="934000" />
|
||||
<workItem from="1706356953689" duration="115000" />
|
||||
<workItem from="1706361173670" duration="1284000" />
|
||||
<workItem from="1706391729848" duration="34425000" />
|
||||
<workItem from="1706435225468" duration="742000" />
|
||||
<workItem from="1706437850699" duration="2805000" />
|
||||
<workItem from="1706475738092" duration="3224000" />
|
||||
<workItem from="1706492338852" duration="2344000" />
|
||||
<workItem from="1706502030301" duration="606000" />
|
||||
<workItem from="1706504263000" duration="1104000" />
|
||||
<workItem from="1706538019385" duration="1260000" />
|
||||
<workItem from="1706569829363" duration="2355000" />
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
<option name="version" value="3" />
|
||||
</component>
|
||||
<component name="VcsManagerConfiguration">
|
||||
<option name="CLEAR_INITIAL_COMMIT_MESSAGE" value="true" />
|
||||
</component>
|
||||
<component name="XDebuggerManager">
|
||||
<breakpoint-manager>
|
||||
<breakpoints>
|
||||
<line-breakpoint enabled="true" type="DotNet Breakpoints">
|
||||
<url>file://$PROJECT_DIR$/comissions.app.api/Controllers/SellerProfileController.cs</url>
|
||||
<line>143</line>
|
||||
<properties documentPath="$PROJECT_DIR$/ArtPlatform.API/Controllers/SellerProfileController.cs" initialLine="97" containingFunctionPresentation="Method 'AddPortfolio'">
|
||||
<startOffsets>
|
||||
<option value="6590" />
|
||||
</startOffsets>
|
||||
<endOffsets>
|
||||
<option value="6624" />
|
||||
</endOffsets>
|
||||
</properties>
|
||||
<option name="timeStamp" value="12" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DotNet Breakpoints">
|
||||
<url>file://$PROJECT_DIR$/comissions.app.api/Controllers/SellerProfileController.cs</url>
|
||||
<line>141</line>
|
||||
<properties documentPath="$PROJECT_DIR$/ArtPlatform.API/Controllers/SellerProfileController.cs" initialLine="95" containingFunctionPresentation="Method 'AddPortfolio'">
|
||||
<startOffsets>
|
||||
<option value="6413" />
|
||||
</startOffsets>
|
||||
<endOffsets>
|
||||
<option value="6443" />
|
||||
</endOffsets>
|
||||
</properties>
|
||||
<option name="timeStamp" value="13" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DotNet Breakpoints">
|
||||
<url>file://$PROJECT_DIR$/comissions.app.api/Controllers/OrderController.cs</url>
|
||||
<line>60</line>
|
||||
<properties documentPath="$PROJECT_DIR$/ArtPlatform.API/Controllers/OrderController.cs" initialLine="60" containingFunctionPresentation="Method 'ProcessWebhookEvent'">
|
||||
<startOffsets>
|
||||
<option value="2514" />
|
||||
</startOffsets>
|
||||
<endOffsets>
|
||||
<option value="2563" />
|
||||
</endOffsets>
|
||||
</properties>
|
||||
<option name="timeStamp" value="29" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DotNet Breakpoints">
|
||||
<url>file://$PROJECT_DIR$/comissions.app.api/Controllers/OrderController.cs</url>
|
||||
<line>47</line>
|
||||
<properties documentPath="$PROJECT_DIR$/ArtPlatform.API/Controllers/OrderController.cs" initialLine="47" containingFunctionPresentation="Method 'ProcessWebhookEvent'">
|
||||
<startOffsets>
|
||||
<option value="1951" />
|
||||
</startOffsets>
|
||||
<endOffsets>
|
||||
<option value="2010" />
|
||||
</endOffsets>
|
||||
</properties>
|
||||
<option name="timeStamp" value="31" />
|
||||
</line-breakpoint>
|
||||
</breakpoints>
|
||||
</breakpoint-manager>
|
||||
<pin-to-top-manager>
|
||||
<pinned-members>
|
||||
<PinnedItemInfo parentTag="Type#System.Security.Claims.Claim" memberName="Subject" />
|
||||
<PinnedItemInfo parentTag="Type#System.Security.Claims.ClaimsIdentity" memberName="Claims" />
|
||||
</pinned-members>
|
||||
</pin-to-top-manager>
|
||||
</component>
|
||||
</project>
|
13
src/.idea/.idea.comissions.app/.idea/.gitignore
generated
vendored
Normal file
13
src/.idea/.idea.comissions.app/.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Rider ignored files
|
||||
/modules.xml
|
||||
/contentModel.xml
|
||||
/projectSettingsUpdater.xml
|
||||
/.idea.ArtPlatform.Database.iml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
1
src/.idea/.idea.comissions.app/.idea/.name
generated
Normal file
1
src/.idea/.idea.comissions.app/.idea/.name
generated
Normal file
@ -0,0 +1 @@
|
||||
comissions.app
|
20
src/.idea/.idea.comissions.app/.idea/aws.xml
generated
Normal file
20
src/.idea/.idea.comissions.app/.idea/aws.xml
generated
Normal file
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="accountSettings">
|
||||
<option name="activeProfile" value="profile:default" />
|
||||
<option name="activeRegion" value="us-east-1" />
|
||||
<option name="recentlyUsedProfiles">
|
||||
<list>
|
||||
<option value="profile:default" />
|
||||
</list>
|
||||
</option>
|
||||
<option name="recentlyUsedRegions">
|
||||
<list>
|
||||
<option value="us-east-1" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="explorerToolWindow">
|
||||
<option name="selectedTab" value="Amazon Q + CodeWhisperer" />
|
||||
</component>
|
||||
</project>
|
19
src/.idea/.idea.comissions.app/.idea/dataSources.xml
generated
Normal file
19
src/.idea/.idea.comissions.app/.idea/dataSources.xml
generated
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||
<data-source source="LOCAL" name="postgres@localhost" uuid="f139dccd-eb47-4ad5-bb4f-f457f16ec1b7">
|
||||
<driver-ref>postgresql</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
|
||||
<jdbc-url>jdbc:postgresql://localhost:5432/postgres</jdbc-url>
|
||||
<working-dir>$ProjectFileDir$</working-dir>
|
||||
</data-source>
|
||||
<data-source source="LOCAL" name="artplatform@localhost" uuid="e4a3d98b-bfa1-4036-a59a-24d9e362740e">
|
||||
<driver-ref>postgresql</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
|
||||
<jdbc-url>jdbc:postgresql://localhost:5432/artplatform</jdbc-url>
|
||||
<working-dir>$ProjectFileDir$</working-dir>
|
||||
</data-source>
|
||||
</component>
|
||||
</project>
|
4
src/.idea/.idea.comissions.app/.idea/encodings.xml
generated
Normal file
4
src/.idea/.idea.comissions.app/.idea/encodings.xml
generated
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
|
||||
</project>
|
8
src/.idea/.idea.comissions.app/.idea/indexLayout.xml
generated
Normal file
8
src/.idea/.idea.comissions.app/.idea/indexLayout.xml
generated
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="UserContentModel">
|
||||
<attachedFolders />
|
||||
<explicitIncludes />
|
||||
<explicitExcludes />
|
||||
</component>
|
||||
</project>
|
6
src/.idea/.idea.comissions.app/.idea/vcs.xml
generated
Normal file
6
src/.idea/.idea.comissions.app/.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
11
src/comissions.app.api/Auth0.Login.CustomAction
Normal file
11
src/comissions.app.api/Auth0.Login.CustomAction
Normal file
@ -0,0 +1,11 @@
|
||||
const namespace = 'http://schemas.microsoft.com/ws/2008/06/identity/claims';
|
||||
exports.onExecutePostLogin = async (event, api) => {{
|
||||
api.accessToken.setCustomClaim(namespace+'/emailaddress', event.user.email);
|
||||
api.accessToken.setCustomClaim(namespace+'/name', event.user.nickname);
|
||||
var assignedRoles = event.authorization?.roles;
|
||||
if(assignedRoles!=null && assignedRoles.length>0){
|
||||
for(var role in assignedRoles){
|
||||
api.accessToken.setCustomClaim(namespace+'role', assignedRoles[role]);
|
||||
}
|
||||
}
|
||||
}}
|
@ -0,0 +1,96 @@
|
||||
using comissions.app.api.Extensions;
|
||||
using ArtPlatform.Database;
|
||||
using ArtPlatform.Database.Entities;
|
||||
using comissions.app.database;
|
||||
using comissions.app.database.Entities;
|
||||
using comissions.app.database.Enums;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace comissions.app.api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Authorize("admin")]
|
||||
[Route("api/admin/[controller]")]
|
||||
public class AdminOrdersController:ControllerBase
|
||||
{
|
||||
private readonly ApplicationDbContext _dbContext;
|
||||
|
||||
public AdminOrdersController(ApplicationDbContext dbContext)
|
||||
{
|
||||
_dbContext = dbContext;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetOrders(string search="", int offset = 0, int pageSize = 10)
|
||||
{
|
||||
var orders = _dbContext.SellerServiceOrders.Include(x=>x.Seller).ThenInclude(x=>x.User).Include(x=>x.Buyer)
|
||||
.Where(x=>x.Seller.User.DisplayName.Contains(search)
|
||||
|| x.Seller.User.Email.Contains(search)
|
||||
|| x.Buyer.DisplayName.Contains(search)
|
||||
|| x.Buyer.Email.Contains(search))
|
||||
.Skip(offset).Take(pageSize).ToList();
|
||||
return Ok(orders);
|
||||
}
|
||||
|
||||
[HttpGet("Count")]
|
||||
public async Task<IActionResult> GetOrdersCount(string search="")
|
||||
{
|
||||
var result = _dbContext.SellerServiceOrders.Include(x=>x.Seller).ThenInclude(x=>x.User).Include(x=>x.Buyer)
|
||||
.Where(x=>x.Seller.User.DisplayName.Contains(search)
|
||||
|| x.Seller.User.Email.Contains(search)
|
||||
|| x.Buyer.DisplayName.Contains(search)
|
||||
|| x.Buyer.Email.Contains(search))
|
||||
.Count();
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet("{orderId:int}")]
|
||||
public async Task<IActionResult> GetOrder(int orderId)
|
||||
{
|
||||
var order = await _dbContext.SellerServiceOrders.Include(x=>x.Seller).ThenInclude(x=>x.User).Include(x=>x.Buyer)
|
||||
.FirstOrDefaultAsync(x=>x.Id==orderId);
|
||||
|
||||
if (order == null)
|
||||
return NotFound("Order not found.");
|
||||
|
||||
return Ok(order);
|
||||
}
|
||||
|
||||
[HttpPost("{orderId:int}")]
|
||||
public async Task<IActionResult> SendMessage(int orderId, [FromBody]string message)
|
||||
{
|
||||
var order = await _dbContext.SellerServiceOrders.Include(x=>x.Seller).ThenInclude(x=>x.User).Include(x=>x.Buyer)
|
||||
.FirstOrDefaultAsync(x=>x.Id==orderId);
|
||||
|
||||
if (order == null)
|
||||
return NotFound("Order not found.");
|
||||
|
||||
order.Messages.Add(new SellerServiceOrderMessage()
|
||||
{
|
||||
Message = message,
|
||||
SenderId = User.GetUserId(),
|
||||
SentAt = DateTime.UtcNow
|
||||
});
|
||||
_dbContext.SellerServiceOrders.Update(order);
|
||||
await _dbContext.SaveChangesAsync();
|
||||
return Ok(order);
|
||||
}
|
||||
|
||||
|
||||
[HttpPut("{orderId:int}/Terminate")]
|
||||
public async Task<IActionResult> TerminateOrder(int orderId)
|
||||
{
|
||||
var order = await _dbContext.SellerServiceOrders.Include(x=>x.Seller).ThenInclude(x=>x.User).Include(x=>x.Buyer)
|
||||
.FirstOrDefaultAsync(x=>x.Id==orderId);
|
||||
|
||||
if (order == null)
|
||||
return NotFound("Order not found.");
|
||||
|
||||
order.Status = EnumOrderStatus.Cancelled;
|
||||
_dbContext.SellerServiceOrders.Update(order);
|
||||
await _dbContext.SaveChangesAsync();
|
||||
return Ok(order);
|
||||
}
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
using comissions.app.api.Models.SellerProfileRequest;
|
||||
using ArtPlatform.Database;
|
||||
using ArtPlatform.Database.Entities;
|
||||
using comissions.app.database;
|
||||
using comissions.app.database.Entities;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace comissions.app.api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Authorize("admin")]
|
||||
[Route("api/admin/[controller]")]
|
||||
public class AdminSellerRequestsController : Controller
|
||||
{
|
||||
private readonly ApplicationDbContext _dbContext;
|
||||
|
||||
public AdminSellerRequestsController(ApplicationDbContext dbContext)
|
||||
{
|
||||
_dbContext = dbContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of all of the requests from users to become a seller.
|
||||
/// </summary>
|
||||
/// <param name="offset"> The offset to start at.</param>
|
||||
/// <param name="pageSize"> The amount of records to return.</param>
|
||||
/// <returns>A list of seller profile requests</returns>
|
||||
[HttpGet]
|
||||
[Authorize("read:seller-profile-request")]
|
||||
public async Task<IActionResult> GetSellerRequests(int offset = 0, int pageSize = 10)
|
||||
{
|
||||
var requests = _dbContext.SellerProfileRequests.Skip(offset).Take(pageSize).ToList();
|
||||
var result = requests.Select(x=>x.ToModel()).ToList();
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the amount of requests there are from users to become a seller.
|
||||
/// </summary>
|
||||
/// <returns>The number of requests.</returns>
|
||||
[HttpGet]
|
||||
[Authorize("read:seller-profile-request")]
|
||||
[Route("Count")]
|
||||
public async Task<IActionResult> GetSellerRequestsCount()
|
||||
{
|
||||
var result = _dbContext.SellerProfileRequests.Count();
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Accepts a request to become a seller from a user.
|
||||
/// </summary>
|
||||
/// <param name="userId">The ID of the user to accept the request for.</param>
|
||||
/// <returns>The new seller profile.</returns>
|
||||
[HttpPut]
|
||||
[Authorize("write:seller-profile-request")]
|
||||
[Route("{userId}")]
|
||||
public async Task<IActionResult> AcceptSellerRequest(string userId)
|
||||
{
|
||||
var request = await _dbContext.SellerProfileRequests.FirstOrDefaultAsync(request=>request.UserId==userId);
|
||||
|
||||
if(request==null)
|
||||
return NotFound("No request for that user exists.");
|
||||
|
||||
if (request.Accepted == true)
|
||||
return BadRequest("User is already a seller.");
|
||||
|
||||
request.Accepted = true;
|
||||
request.AcceptedDate = DateTime.UtcNow;
|
||||
|
||||
var newSellerProfile = new UserSellerProfile()
|
||||
{
|
||||
UserId = userId,
|
||||
AgeRestricted = false,
|
||||
Biography = string.Empty,
|
||||
SocialMediaLinks = new List<string>(){}
|
||||
};
|
||||
_dbContext.UserSellerProfiles.Add(newSellerProfile);
|
||||
request = _dbContext.SellerProfileRequests.Update(request).Entity;
|
||||
await _dbContext.SaveChangesAsync();
|
||||
var result = request.ToModel();
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
@ -0,0 +1,142 @@
|
||||
using comissions.app.api.Extensions;
|
||||
using ArtPlatform.Database;
|
||||
using comissions.app.database;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http.HttpResults;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace comissions.app.api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Authorize("admin")]
|
||||
[Route("api/admin/[controller]")]
|
||||
public class AdminSellersController:ControllerBase
|
||||
{
|
||||
private readonly ApplicationDbContext _dbContext;
|
||||
|
||||
public AdminSellersController(ApplicationDbContext dbContext)
|
||||
{
|
||||
_dbContext = dbContext;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetSellers(string search="", int offset = 0, int pageSize = 10)
|
||||
{
|
||||
var sellers = await _dbContext.UserSellerProfiles.Include(x=>x.User)
|
||||
.Where(x=>x.User.DisplayName.Contains(search) || x.User.Email.Contains(search))
|
||||
.Skip(offset).Take(pageSize).ToListAsync();
|
||||
return Ok(sellers);
|
||||
}
|
||||
|
||||
[HttpGet("Count")]
|
||||
public async Task<IActionResult> GetSellersCount(string search="")
|
||||
{
|
||||
var result = await _dbContext.UserSellerProfiles.Include(x=>x.User)
|
||||
.Where(x=>x.User.DisplayName.Contains(search) || x.User.Email.Contains(search))
|
||||
.CountAsync();
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet("{sellerId:int}")]
|
||||
public async Task<IActionResult> GetSeller(int sellerId)
|
||||
{
|
||||
var seller = await _dbContext.UserSellerProfiles.Include(x=>x.User)
|
||||
.FirstOrDefaultAsync(x=>x.Id==sellerId);
|
||||
|
||||
if (seller == null)
|
||||
return NotFound("Seller not found.");
|
||||
|
||||
return Ok(seller);
|
||||
}
|
||||
|
||||
[HttpGet("{sellerId:int}/Orders")]
|
||||
public async Task<IActionResult> GetSellerOrders(int sellerId)
|
||||
{
|
||||
var seller = _dbContext.UserSellerProfiles.Include(x=>x.User)
|
||||
.FirstOrDefault(x=>x.Id==sellerId);
|
||||
|
||||
if (seller == null)
|
||||
return NotFound("Seller not found.");
|
||||
|
||||
var orders = await _dbContext.SellerServiceOrders.Where(x=>x.SellerId==sellerId).ToListAsync();
|
||||
return Ok(orders);
|
||||
}
|
||||
|
||||
[HttpPut("{sellerId:int}/Suspend")]
|
||||
public async Task<IActionResult> SuspendSeller(int sellerId, [FromQuery]string reason, [FromQuery]int days)
|
||||
{
|
||||
var seller = _dbContext.UserSellerProfiles.FirstOrDefault(x=>x.Id==sellerId);
|
||||
|
||||
if (seller == null)
|
||||
return NotFound("Seller not found.");
|
||||
|
||||
if (seller.Suspended)
|
||||
return BadRequest("Seller is already suspended.");
|
||||
|
||||
seller.Suspended = true;
|
||||
seller.SuspendedDate = DateTime.UtcNow;
|
||||
seller.UnsuspendDate = DateTime.UtcNow.AddDays(days);
|
||||
seller.SuspendedReason = reason;
|
||||
seller.SuspendAdminId = User.GetUserId();
|
||||
_dbContext.UserSellerProfiles.Update(seller);
|
||||
|
||||
await _dbContext.SaveChangesAsync();
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpPut("{sellerId:int}/Unsuspend")]
|
||||
public async Task<IActionResult> UnsuspendSeller(int sellerId)
|
||||
{
|
||||
var seller = _dbContext.UserSellerProfiles.FirstOrDefault(x=>x.Id==sellerId);
|
||||
|
||||
if (seller == null)
|
||||
return NotFound("Seller not found.");
|
||||
|
||||
if (!seller.Suspended)
|
||||
return BadRequest("Seller is not suspended.");
|
||||
|
||||
seller.Suspended = false;
|
||||
seller.SuspendedDate = null;
|
||||
seller.UnsuspendDate = null;
|
||||
seller.SuspendedReason = null;
|
||||
seller.SuspendAdminId = null;
|
||||
_dbContext.UserSellerProfiles.Update(seller);
|
||||
|
||||
await _dbContext.SaveChangesAsync();
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpPut("{sellerId:int}/Terminate")]
|
||||
public async Task<IActionResult> TerminateSeller(int sellerId)
|
||||
{
|
||||
var seller = _dbContext.UserSellerProfiles.FirstOrDefault(x=>x.Id==sellerId);
|
||||
|
||||
if (seller == null)
|
||||
return NotFound("Seller not found.");
|
||||
|
||||
if (!seller.Suspended)
|
||||
return BadRequest("Seller is not suspended.");
|
||||
|
||||
_dbContext.UserSellerProfiles.Remove(seller);
|
||||
await _dbContext.SaveChangesAsync();
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpPut("{sellerId:int}/SetBiography")]
|
||||
public async Task<IActionResult> SetBiography(int sellerId, [FromBody]string biography)
|
||||
{
|
||||
var seller = _dbContext.UserSellerProfiles.FirstOrDefault(x=>x.Id==sellerId);
|
||||
|
||||
if (seller == null)
|
||||
return NotFound("Seller not found.");
|
||||
|
||||
if (!seller.Suspended)
|
||||
return BadRequest("Seller is not suspended.");
|
||||
|
||||
seller.Biography = biography;
|
||||
_dbContext.UserSellerProfiles.Update(seller);
|
||||
await _dbContext.SaveChangesAsync();
|
||||
return Ok();
|
||||
}
|
||||
}
|
162
src/comissions.app.api/Controllers/Admin/AdminUsersController.cs
Normal file
162
src/comissions.app.api/Controllers/Admin/AdminUsersController.cs
Normal file
@ -0,0 +1,162 @@
|
||||
using comissions.app.api.Extensions;
|
||||
using ArtPlatform.Database;
|
||||
using comissions.app.database;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace comissions.app.api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Authorize("admin")]
|
||||
[Route("api/admin/[controller]")]
|
||||
public class AdminUsersController:ControllerBase
|
||||
{
|
||||
private readonly ApplicationDbContext _dbContext;
|
||||
|
||||
public AdminUsersController(ApplicationDbContext dbContext)
|
||||
{
|
||||
_dbContext = dbContext;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetUsers(string search="", int offset = 0, int pageSize = 10)
|
||||
{
|
||||
var users = await _dbContext.Users
|
||||
.Where(x=>x.DisplayName.Contains(search) || x.Email.Contains(search))
|
||||
.Skip(offset).Take(pageSize).ToListAsync();
|
||||
return Ok(users);
|
||||
}
|
||||
|
||||
[HttpGet("Count")]
|
||||
public async Task<IActionResult> GetUsersCount(string search="")
|
||||
{
|
||||
var result = await _dbContext.Users
|
||||
.Where(x=>x.DisplayName.Contains(search) || x.Email.Contains(search))
|
||||
.CountAsync();
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet("{userId}")]
|
||||
public async Task<IActionResult> GetUser(string userId)
|
||||
{
|
||||
var user = await _dbContext.Users.FirstOrDefaultAsync(x=>x.Id==userId);
|
||||
|
||||
if (user == null)
|
||||
return NotFound("User not found.");
|
||||
|
||||
return Ok(user);
|
||||
}
|
||||
|
||||
[HttpGet("{userId}/Orders")]
|
||||
public async Task<IActionResult> GetUserOrders(string userId)
|
||||
{
|
||||
var user = await _dbContext.Users.Include(x=>x.Orders).FirstOrDefaultAsync(x=>x.Id==userId);
|
||||
|
||||
if (user == null)
|
||||
return NotFound("User not found.");
|
||||
|
||||
return Ok(user.Orders);
|
||||
}
|
||||
|
||||
[HttpPut("{userId}/Suspend")]
|
||||
public async Task<IActionResult> SuspendUser(string userId, [FromQuery]string reason, [FromQuery]int days)
|
||||
{
|
||||
var user = await _dbContext.Users.FirstOrDefaultAsync(x=>x.Id==userId);
|
||||
|
||||
if (user == null)
|
||||
return NotFound("User not found.");
|
||||
|
||||
user.Suspended = true;
|
||||
user.SuspendedDate = DateTime.UtcNow;
|
||||
user.SuspendedReason = reason;
|
||||
user.SuspendAdminId = User.GetUserId();
|
||||
user.UnsuspendDate = DateTime.UtcNow.AddDays(days);
|
||||
_dbContext.Users.Update(user);
|
||||
await _dbContext.SaveChangesAsync();
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpPut("{userId}/Unsuspend")]
|
||||
public async Task<IActionResult> UnsuspendUser(string userId)
|
||||
{
|
||||
var user = await _dbContext.Users.FirstOrDefaultAsync(x=>x.Id==userId);
|
||||
|
||||
if (user == null)
|
||||
return NotFound("User not found.");
|
||||
|
||||
user.Suspended = false;
|
||||
user.SuspendedDate = null;
|
||||
user.SuspendedReason = null;
|
||||
user.SuspendAdminId = null;
|
||||
user.UnsuspendDate = null;
|
||||
_dbContext.Users.Update(user);
|
||||
await _dbContext.SaveChangesAsync();
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpPut("{userId}/Ban")]
|
||||
public async Task<IActionResult> BanUser(string userId, [FromQuery]string reason, [FromQuery]int days)
|
||||
{
|
||||
var user = await _dbContext.Users.FirstOrDefaultAsync(x=>x.Id==userId);
|
||||
|
||||
if (user == null)
|
||||
return NotFound("User not found.");
|
||||
|
||||
user.Banned = true;
|
||||
user.BannedDate = DateTime.UtcNow;
|
||||
user.BannedReason = reason;
|
||||
user.BanAdminId = User.GetUserId();
|
||||
user.UnbanDate = DateTime.UtcNow.AddDays(days);
|
||||
_dbContext.Users.Update(user);
|
||||
await _dbContext.SaveChangesAsync();
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpPut("{userId}/Unban")]
|
||||
public async Task<IActionResult> UnbanUser(string userId)
|
||||
{
|
||||
var user = await _dbContext.Users.FirstOrDefaultAsync(x=>x.Id==userId);
|
||||
|
||||
if (user == null)
|
||||
return NotFound("User not found.");
|
||||
|
||||
user.Banned = false;
|
||||
user.BannedDate = null;
|
||||
user.BannedReason = null;
|
||||
user.BanAdminId = null;
|
||||
user.UnbanDate = null;
|
||||
_dbContext.Users.Update(user);
|
||||
await _dbContext.SaveChangesAsync();
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpPut("{userId}/SetDisplayName")]
|
||||
public async Task<IActionResult> SetDisplayName(string userId, [FromBody]string displayName)
|
||||
{
|
||||
var user = await _dbContext.Users.FirstOrDefaultAsync(x=>x.Id==userId);
|
||||
|
||||
if (user == null)
|
||||
return NotFound("User not found.");
|
||||
|
||||
user.DisplayName = displayName;
|
||||
_dbContext.Users.Update(user);
|
||||
await _dbContext.SaveChangesAsync();
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpPut("{userId}/SetBiography")]
|
||||
public async Task<IActionResult> SetBiography(string userId, [FromBody]string biography)
|
||||
{
|
||||
var user = await _dbContext.Users.FirstOrDefaultAsync(x=>x.Id==userId);
|
||||
|
||||
if (user == null)
|
||||
return NotFound("User not found.");
|
||||
|
||||
user.Biography = biography;
|
||||
_dbContext.Users.Update(user);
|
||||
await _dbContext.SaveChangesAsync();
|
||||
return Ok();
|
||||
}
|
||||
|
||||
}
|
120
src/comissions.app.api/Controllers/DiscoveryController.cs
Normal file
120
src/comissions.app.api/Controllers/DiscoveryController.cs
Normal file
@ -0,0 +1,120 @@
|
||||
using comissions.app.api.Models.SellerProfile;
|
||||
using comissions.app.api.Models.SellerService;
|
||||
using ArtPlatform.Database;
|
||||
using comissions.app.api.Models.Discovery;
|
||||
using comissions.app.database;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace comissions.app.api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class DiscoveryController : Controller
|
||||
{
|
||||
private readonly ApplicationDbContext _dbContext;
|
||||
|
||||
public DiscoveryController(ApplicationDbContext dbContext)
|
||||
{
|
||||
_dbContext = dbContext;
|
||||
}
|
||||
|
||||
|
||||
[HttpGet]
|
||||
[Route("Sellers")]
|
||||
public async Task<IActionResult> GetSellers(string search="",int offset = 0, int pageSize = 10)
|
||||
{
|
||||
var sellers = await _dbContext.UserSellerProfiles
|
||||
.Where(x=>x.User.DisplayName.Contains(search))
|
||||
.Include(x=>x.User)
|
||||
.Skip(offset).Take(pageSize).ToListAsync();
|
||||
var result = sellers.Select(x=>x.ToDiscoveryModel()).ToList();
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route("Sellers/Count")]
|
||||
public async Task<IActionResult> GetSellersCount(string search="")
|
||||
{
|
||||
var result = await _dbContext.UserSellerProfiles
|
||||
.Where(x=>x.User.DisplayName.Contains(search))
|
||||
.Include(x=>x.User)
|
||||
.CountAsync();
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route("Sellers/{sellerId:int}/Services")]
|
||||
public async Task<IActionResult> GetSellerServices(int sellerId, int offset = 0, int pageSize = 10)
|
||||
{
|
||||
var seller = await _dbContext.UserSellerProfiles
|
||||
.Include(x=>x.User)
|
||||
.FirstOrDefaultAsync(x=>x.Id==sellerId);
|
||||
if(seller==null)
|
||||
return NotFound("Seller not found.");
|
||||
var sellerServices = await _dbContext.SellerServices
|
||||
.Include(x=>x.Reviews)
|
||||
.Where(x=>x.SellerProfileId==sellerId && !x.Archived)
|
||||
.Skip(offset).Take(pageSize).ToListAsync();
|
||||
var result = sellerServices.Select(x=>x.ToModel()).ToList();
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route("Sellers/{sellerId:int}/Services/Count")]
|
||||
public async Task<IActionResult> GetSellerServicesCount(int sellerId)
|
||||
{
|
||||
var seller = await _dbContext.UserSellerProfiles
|
||||
.Include(x=>x.User)
|
||||
.FirstOrDefaultAsync(x=>x.Id==sellerId);
|
||||
if(seller==null)
|
||||
return NotFound("Seller not found.");
|
||||
var sellerServices = await _dbContext.SellerServices
|
||||
.Include(x=>x.Reviews)
|
||||
.Where(x=>x.SellerProfileId==sellerId && !x.Archived)
|
||||
.ToListAsync();
|
||||
var result = sellerServices.Count;
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route("Sellers/{sellerId:int}/Services/{serviceId:int}/Reviews")]
|
||||
public async Task<IActionResult> GetSellerServiceReviews(int sellerId, int serviceId, int offset = 0, int pageSize = 10)
|
||||
{
|
||||
var seller = await _dbContext.UserSellerProfiles
|
||||
.Include(x=>x.User)
|
||||
.FirstOrDefaultAsync(x=>x.Id==sellerId);
|
||||
if(seller==null)
|
||||
return NotFound("Seller not found.");
|
||||
var sellerService = await _dbContext.SellerServices
|
||||
.Include(x=>x.Reviews).ThenInclude(x=>x.Reviewer)
|
||||
.FirstOrDefaultAsync(x=>x.Id==serviceId);
|
||||
if(sellerService==null)
|
||||
return NotFound("Seller service not found.");
|
||||
var result = sellerService.Reviews.Select(x=> new DiscoveryReviewModel()
|
||||
{
|
||||
Rating = x.Rating,
|
||||
WriterDisplayName = x.Reviewer.DisplayName,
|
||||
WriterId = x.ReviewerId,
|
||||
}).ToList();
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route("Sellers/{sellerId:int}/Services/{serviceId:int}/Reviews/Count")]
|
||||
public async Task<IActionResult> GetSellerServiceReviewsCount(int sellerId, int serviceId)
|
||||
{
|
||||
var seller = await _dbContext.UserSellerProfiles
|
||||
.Include(x=>x.User)
|
||||
.FirstOrDefaultAsync(x=>x.Id==sellerId);
|
||||
if(seller==null)
|
||||
return NotFound("Seller not found.");
|
||||
var sellerService = await _dbContext.SellerServices
|
||||
.Include(x=>x.Reviews).ThenInclude(x=>x.Reviewer)
|
||||
.FirstOrDefaultAsync(x=>x.Id==serviceId);
|
||||
if(sellerService==null)
|
||||
return NotFound("Seller service not found.");
|
||||
var result = sellerService.Reviews.Count;
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
463
src/comissions.app.api/Controllers/OrderController.cs
Normal file
463
src/comissions.app.api/Controllers/OrderController.cs
Normal file
@ -0,0 +1,463 @@
|
||||
using comissions.app.api.Extensions;
|
||||
using ArtPlatform.Database;
|
||||
using ArtPlatform.Database.Entities;
|
||||
using comissions.app.api.Models.Order;
|
||||
using comissions.app.api.Services.Payment;
|
||||
using comissions.app.api.Services.Storage;
|
||||
using comissions.app.database;
|
||||
using comissions.app.database.Entities;
|
||||
using comissions.app.database.Enums;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Stripe;
|
||||
using Stripe.Checkout;
|
||||
|
||||
namespace comissions.app.api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class OrderController : Controller
|
||||
{
|
||||
private readonly ApplicationDbContext _dbContext;
|
||||
private readonly IStorageService _storageService;
|
||||
private readonly IPaymentService _paymentService;
|
||||
private readonly string _webHookSecret;
|
||||
|
||||
public OrderController(ApplicationDbContext dbContext, IConfiguration configuration, IStorageService storageService, IPaymentService paymentService)
|
||||
{
|
||||
_paymentService = paymentService;
|
||||
_storageService = storageService;
|
||||
_dbContext = dbContext;
|
||||
_webHookSecret = configuration.GetValue<string>("Stripe:WebHookSecret");
|
||||
}
|
||||
|
||||
[HttpPost("PaymentWebhook")]
|
||||
public async Task<IActionResult> ProcessWebhookEvent()
|
||||
{
|
||||
var json = await new StreamReader(HttpContext.Request.Body).ReadToEndAsync();
|
||||
|
||||
// If you are testing your webhook locally with the Stripe CLI you
|
||||
// can find the endpoint's secret by running `stripe listen`
|
||||
// Otherwise, find your endpoint's secret in your webhook settings
|
||||
// in the Developer Dashboard
|
||||
var stripeEvent = EventUtility.ConstructEvent(json, Request.Headers["Stripe-Signature"], _webHookSecret);
|
||||
|
||||
if (stripeEvent.Type == Events.CheckoutSessionExpired)
|
||||
{
|
||||
var session = stripeEvent.Data.Object as Session;
|
||||
var connectedAccountId = stripeEvent.Account;
|
||||
var orderId = session.LineItems.First().Price.Product.Name;
|
||||
var order = await _dbContext.SellerServiceOrders
|
||||
.Include(x=>x.Seller)
|
||||
.Include(x=>x.Buyer)
|
||||
.Include(x=>x.SellerService)
|
||||
.FirstOrDefaultAsync(x=>x.Id==int.Parse(orderId));
|
||||
if (order != null && order.Status == EnumOrderStatus.WaitingForPayment)
|
||||
{
|
||||
order.PaymentUrl = null;
|
||||
}
|
||||
}
|
||||
else if (stripeEvent.Type == Events.CheckoutSessionCompleted)
|
||||
{
|
||||
var session = stripeEvent.Data.Object as Session;
|
||||
var connectedAccountId = stripeEvent.Account;
|
||||
var orderId = session.Metadata["/OrderId"];
|
||||
var order = await _dbContext.SellerServiceOrders
|
||||
.Include(x=>x.Seller)
|
||||
.Include(x=>x.SellerService)
|
||||
.FirstOrDefaultAsync(x=>x.Id==int.Parse(orderId));
|
||||
if (order != null && order.Seller.StripeAccountId==connectedAccountId && order.Status == EnumOrderStatus.WaitingForPayment)
|
||||
{
|
||||
if (order.Seller.PrepaymentRequired)
|
||||
order.Status = EnumOrderStatus.InProgress;
|
||||
else
|
||||
order.Status = EnumOrderStatus.Completed;
|
||||
}
|
||||
}
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route("/api/Orders")]
|
||||
[Authorize("read:orders")]
|
||||
public async Task<IActionResult> GetOrders(int offset = 0, int pageSize = 10, EnumOrderStatus? status = null)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var orders = await _dbContext.SellerServiceOrders
|
||||
.Where(x => x.BuyerId == userId && status==null ? true : status==x.Status)
|
||||
.Skip(offset).Take(pageSize).ToListAsync();
|
||||
var result = orders.Select(x => x.ToModel()).ToList();
|
||||
return Ok(result);
|
||||
}
|
||||
[HttpGet]
|
||||
[Route("/api/Orders/{orderId:int}")]
|
||||
[Authorize("read:orders")]
|
||||
public async Task<IActionResult> GetOrder(int orderId,int offset = 0, int pageSize = 10, EnumOrderStatus? status = null)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var order = await _dbContext.SellerServiceOrders
|
||||
.FirstAsync(x => x.Id==orderId && x.BuyerId == userId && status == null ? true : status == x.Status);
|
||||
var result = order.ToModel();
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Route("/api/Sellers/{sellerId:int}/Services/{serviceId:int}")]
|
||||
[Authorize("write:orders")]
|
||||
public async Task<IActionResult> CreateOrder(int sellerId, int serviceId)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var seller = await _dbContext.UserSellerProfiles
|
||||
.Include(x=>x.User)
|
||||
.FirstOrDefaultAsync(x=>x.Id==sellerId);
|
||||
if(seller==null)
|
||||
return NotFound("Seller not found.");
|
||||
if(seller.Suspended)
|
||||
return NotFound("Seller is suspended.");
|
||||
|
||||
var service = await _dbContext.SellerServices
|
||||
.Include(x=>x.Reviews)
|
||||
.FirstOrDefaultAsync(x=>x.Id==serviceId);
|
||||
if(service==null)
|
||||
return NotFound("Service not found.");
|
||||
|
||||
if(service.Archived)
|
||||
return BadRequest("Service is archived.");
|
||||
|
||||
if(_dbContext.SellerServiceOrders.Where(x=>x.BuyerId==userId && x.Status!=EnumOrderStatus.Completed && x.Status!=EnumOrderStatus.Cancelled).Count()>=3)
|
||||
return BadRequest("You already have an order in progress. There is a limit of three at a time.");
|
||||
|
||||
var order = new SellerServiceOrder()
|
||||
{
|
||||
BuyerId = userId,
|
||||
SellerId = seller.Id,
|
||||
SellerServiceId = serviceId,
|
||||
Status = EnumOrderStatus.PendingAcceptance,
|
||||
CreatedDate = DateTime.UtcNow,
|
||||
Price = service.Price,
|
||||
SellerService = service,
|
||||
Buyer = await _dbContext.Users.FirstOrDefaultAsync(x=>x.Id==userId),
|
||||
};
|
||||
order = _dbContext.SellerServiceOrders.Add(order).Entity;
|
||||
await _dbContext.SaveChangesAsync();
|
||||
var result = order.ToModel();
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[Authorize("write:orders")]
|
||||
[Route("/api/Orders/{orderId:int}")]
|
||||
public async Task<IActionResult> CancelOrder(int orderId)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var order = await _dbContext.SellerServiceOrders
|
||||
.Include(x=>x.SellerService)
|
||||
.FirstOrDefaultAsync(x=>x.Id==orderId && x.BuyerId==userId);
|
||||
if(order==null)
|
||||
return NotFound("/Order not found.");
|
||||
if(order.BuyerId!=userId)
|
||||
return BadRequest("You are not the buyer of this order.");
|
||||
if(order.Status==EnumOrderStatus.Completed)
|
||||
return BadRequest("/Order is not in a cancellable state.");
|
||||
order.Status = EnumOrderStatus.Cancelled;
|
||||
order.EndDate = DateTime.UtcNow;
|
||||
order = _dbContext.SellerServiceOrders.Update(order).Entity;
|
||||
await _dbContext.SaveChangesAsync();
|
||||
var result = order.ToModel();
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPut]
|
||||
[Authorize("write:orders")]
|
||||
[Route("/api/Orders/{orderId:int}/AcceptPrice")]
|
||||
public async Task<IActionResult> AcceptPrice(int orderId)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var order = await _dbContext.SellerServiceOrders
|
||||
.Include(x=>x.SellerService)
|
||||
.Include(x=>x.Buyer)
|
||||
.Include(x=>x.Seller)
|
||||
.FirstOrDefaultAsync(x=>x.Id==orderId && x.BuyerId==userId);
|
||||
if(order==null)
|
||||
return NotFound("/Order not found.");
|
||||
if(order.Seller.UserId!=userId)
|
||||
return BadRequest("You are not the seller of this order.");
|
||||
if(order.Status==EnumOrderStatus.Completed)
|
||||
return BadRequest("/Order is already complete.");
|
||||
if(order.Status<EnumOrderStatus.DiscussingRequirements)
|
||||
return BadRequest("/Order has not been started yet.");
|
||||
|
||||
if(string.IsNullOrEmpty(order.PaymentUrl)==false)
|
||||
return BadRequest("/Order has price already been agreed on.");
|
||||
|
||||
if(order.Status==EnumOrderStatus.WaitingForPayment)
|
||||
return BadRequest("/Order is waiting for payment.");
|
||||
|
||||
order.TermsAcceptedDate = DateTime.UtcNow;
|
||||
|
||||
if (order.Seller.PrepaymentRequired)
|
||||
{
|
||||
order.Status = EnumOrderStatus.WaitingForPayment;
|
||||
var url = _paymentService.ChargeForService(order.Id, order.Seller.StripeAccountId, order.Price);
|
||||
order.PaymentUrl = url;
|
||||
}
|
||||
else
|
||||
{
|
||||
order.Status = EnumOrderStatus.InProgress;
|
||||
}
|
||||
|
||||
order = _dbContext.SellerServiceOrders.Update(order).Entity;
|
||||
|
||||
await _dbContext.SaveChangesAsync();
|
||||
var result = order.ToModel();
|
||||
return Ok(result);
|
||||
}
|
||||
[HttpPut]
|
||||
[Authorize("write:orders")]
|
||||
[Route("/api/Orders/{orderId:int}/Payment")]
|
||||
public async Task<IActionResult> Payment(int orderId)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var order = await _dbContext.SellerServiceOrders
|
||||
.Include(x=>x.SellerService)
|
||||
.Include(x=>x.Buyer)
|
||||
.Include(x=>x.Seller)
|
||||
.FirstOrDefaultAsync(x=>x.Id==orderId && x.BuyerId==userId);
|
||||
if(order==null)
|
||||
return NotFound("/Order not found.");
|
||||
if(order.Seller.UserId!=userId)
|
||||
return BadRequest("You are not the seller of this order.");
|
||||
if(order.Status==EnumOrderStatus.Completed)
|
||||
return BadRequest("/Order is already complete.");
|
||||
if(order.Status!=EnumOrderStatus.WaitingForPayment)
|
||||
return BadRequest("/Order does not need to be paid for.");
|
||||
if (order.PaymentUrl != null)
|
||||
return Ok(order.PaymentUrl);
|
||||
var url = _paymentService.ChargeForService(order.Id, order.Seller.StripeAccountId, order.Price);
|
||||
order.PaymentUrl = url;
|
||||
order = _dbContext.SellerServiceOrders.Update(order).Entity;
|
||||
await _dbContext.SaveChangesAsync();
|
||||
return Ok(order.PaymentUrl);
|
||||
}
|
||||
|
||||
[HttpPut]
|
||||
[Authorize("write:orders")]
|
||||
[Route("/api/Orders/{orderId:int}/Accept")]
|
||||
public async Task<IActionResult> Accept(int orderId)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var order = await _dbContext.SellerServiceOrders
|
||||
.Include(x=>x.Seller)
|
||||
.Include(x=>x.SellerService)
|
||||
.FirstOrDefaultAsync(x=>x.Id==orderId && x.BuyerId==userId);
|
||||
if(order==null)
|
||||
return NotFound("/Order not found.");
|
||||
if(order.Seller.UserId!=userId)
|
||||
return BadRequest("You are not the seller of this order.");
|
||||
if(order.Status==EnumOrderStatus.Completed)
|
||||
return BadRequest("/Order is already complete.");
|
||||
if(order.Status<EnumOrderStatus.InProgress)
|
||||
return BadRequest("/Order has not been started yet.");
|
||||
if(order.Status<EnumOrderStatus.PendingReview)
|
||||
return BadRequest("/Order is in progress and not pending review.");
|
||||
if(order.Status==EnumOrderStatus.WaitingForPayment)
|
||||
return BadRequest("/Order is waiting for payment.");
|
||||
|
||||
if(order.Seller.PrepaymentRequired)
|
||||
order.Status = EnumOrderStatus.Completed;
|
||||
else
|
||||
{
|
||||
order.Status = EnumOrderStatus.WaitingForPayment;
|
||||
var url = _paymentService.ChargeForService(order.Id, order.Seller.StripeAccountId, order.Price);
|
||||
order.PaymentUrl = url;
|
||||
}
|
||||
|
||||
order.TermsAcceptedDate = DateTime.UtcNow;
|
||||
order = _dbContext.SellerServiceOrders.Update(order).Entity;
|
||||
await _dbContext.SaveChangesAsync();
|
||||
var result = order.ToModel();
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[Authorize("write:orders")]
|
||||
[Route("/api/Orders/{orderId:int}/Deny")]
|
||||
public async Task<IActionResult> Deny(int orderId)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var order = await _dbContext.SellerServiceOrders
|
||||
.Include(x=>x.Seller)
|
||||
.Include(x=>x.SellerService)
|
||||
.FirstOrDefaultAsync(x=>x.Id==orderId && x.BuyerId==userId);
|
||||
if(order==null)
|
||||
return NotFound("/Order not found.");
|
||||
if(order.Seller.UserId!=userId)
|
||||
return BadRequest("You are not the seller of this order.");
|
||||
if(order.Status==EnumOrderStatus.Completed)
|
||||
return BadRequest("/Order is already complete.");
|
||||
if(order.Status<EnumOrderStatus.InProgress)
|
||||
return BadRequest("/Order has not been started yet.");
|
||||
if(order.Status<EnumOrderStatus.PendingReview)
|
||||
return BadRequest("/Order is in progress and not pending review.");
|
||||
order.Status = EnumOrderStatus.InProgress;
|
||||
order.TermsAcceptedDate = DateTime.UtcNow;
|
||||
order = _dbContext.SellerServiceOrders.Update(order).Entity;
|
||||
await _dbContext.SaveChangesAsync();
|
||||
var result = order.ToModel();
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Authorize("write:orders")]
|
||||
[Route("/api/Orders/{orderId:int}/Review")]
|
||||
public async Task<IActionResult> Review(int orderId, [FromBody] SellerServiceOrderReviewModel model)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var order = await _dbContext.SellerServiceOrders
|
||||
.Include(x=>x.Reviews)
|
||||
.Include(x=>x.Seller)
|
||||
.Include(x=>x.SellerService)
|
||||
.FirstOrDefaultAsync(x=>x.Id==orderId && x.BuyerId==userId);
|
||||
if(order==null)
|
||||
return NotFound("/Order not found.");
|
||||
if(order.BuyerId!=userId)
|
||||
return BadRequest("You are not the buyer of this order.");
|
||||
if(order.Status!=EnumOrderStatus.Completed)
|
||||
return BadRequest("/Order is not complete.");
|
||||
if(order.Reviews.Any(x=>x.SellerServiceOrderId==orderId))
|
||||
return BadRequest("/Order has already been reviewed.");
|
||||
var review = new SellerServiceOrderReview()
|
||||
{
|
||||
SellerServiceOrderId = orderId,
|
||||
SellerServiceId = order.SellerServiceId,
|
||||
Rating = model.Rating,
|
||||
Review = model.Review,
|
||||
ReviewDate = DateTime.UtcNow,
|
||||
ReviewerId = userId,
|
||||
Reviewer = await _dbContext.Users.FirstOrDefaultAsync(x=>x.Id==userId),
|
||||
};
|
||||
await _dbContext.SellerServiceOrderReviews.AddAsync(review);
|
||||
await _dbContext.SaveChangesAsync();
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Authorize("read:orders")]
|
||||
[Route("/api/Orders/{orderId:int}/Messages")]
|
||||
public async Task<IActionResult> GetMessages(int orderId, int offset = 0, int pageSize = 10)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var order = await _dbContext.SellerServiceOrders
|
||||
.Include(x=>x.Seller)
|
||||
.FirstOrDefaultAsync(x=>x.Id==orderId && x.BuyerId==userId);
|
||||
if(order==null)
|
||||
return NotFound("/Order not found.");
|
||||
if(order.BuyerId!=userId && order.Seller.UserId!=userId)
|
||||
return BadRequest("You are not the buyer or seller of this order.");
|
||||
var messages = _dbContext.SellerServiceOrderMessages
|
||||
.Include(x=>x.Sender)
|
||||
.Include(x=>x.Attachments)
|
||||
.OrderBy(x=>x.SentAt)
|
||||
.Where(x=>x.SellerServiceOrderId==orderId)
|
||||
.Skip(offset).Take(pageSize).ToList();
|
||||
var result = messages.Select(x=>x.ToModel()).ToList();
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Authorize("write:orders")]
|
||||
[Route("/api/Orders/{orderId:int}/Message")]
|
||||
public async Task<IActionResult> Message(int orderId, [FromBody] SellerServiceOrderMessageModel model)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var order = await _dbContext.SellerServiceOrders
|
||||
.Include(x=>x.Messages)
|
||||
.Include(x=>x.Seller)
|
||||
.Include(x=>x.SellerService)
|
||||
.FirstOrDefaultAsync(x=>x.Id==orderId && x.BuyerId==userId);
|
||||
if(order==null)
|
||||
return NotFound("/Order not found.");
|
||||
if(order.Status==EnumOrderStatus.Completed || order.Status==EnumOrderStatus.Cancelled)
|
||||
return BadRequest("/Order is already complete.");
|
||||
if(order.BuyerId!=userId && order.Seller.UserId!=userId)
|
||||
return BadRequest("You are not the buyer or seller of this order.");
|
||||
if(order.Status<EnumOrderStatus.Waitlist)
|
||||
return BadRequest("/Order is not accepted.");
|
||||
var message = new SellerServiceOrderMessage()
|
||||
{
|
||||
SellerServiceOrderId = orderId,
|
||||
Message = model.Message,
|
||||
SentAt = DateTime.UtcNow,
|
||||
SenderId = userId,
|
||||
Sender = await _dbContext.Users.FirstOrDefaultAsync(x=>x.Id==userId),
|
||||
};
|
||||
var dbMessage = _dbContext.SellerServiceOrderMessages.Add(message).Entity;
|
||||
await _dbContext.SaveChangesAsync();
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Authorize("write:orders")]
|
||||
[Route("/api/Orders/{orderId:int}/Message/{messageId:int}/Attachment")]
|
||||
public async Task<IActionResult> MessageAttachment(int orderId, int messageId,IFormFile file)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var order = await _dbContext.SellerServiceOrders
|
||||
.Include(x=>x.Messages)
|
||||
.Include(x=>x.Seller)
|
||||
.Include(x=>x.SellerService)
|
||||
.FirstOrDefaultAsync(x=>x.Id==orderId);
|
||||
if(order==null)
|
||||
return NotFound("/Order not found.");
|
||||
if(order.BuyerId!=userId && order.Seller.UserId!=userId)
|
||||
return BadRequest("You are not the buyer or seller of this order.");
|
||||
if(order.Status==EnumOrderStatus.Completed || order.Status==EnumOrderStatus.Cancelled)
|
||||
return BadRequest("/Order is already complete.");
|
||||
if(order.Status<EnumOrderStatus.Waitlist)
|
||||
return BadRequest("/Order is not accepted.");
|
||||
|
||||
var message = _dbContext.SellerServiceOrderMessages.First(x=>x.Id==messageId && x.SellerServiceOrderId==orderId);
|
||||
if(message==null)
|
||||
return BadRequest("Message does not exist or does not belong to this order.");
|
||||
|
||||
var url = await _storageService.UploadImageAsync(file, Guid.NewGuid().ToString());
|
||||
var attachment = new SellerServiceOrderMessageAttachment()
|
||||
{
|
||||
SellerServiceOrderMessageId = message.Id,
|
||||
FileReference = url
|
||||
};
|
||||
_dbContext.SellerServiceOrderMessageAttachments.Add(attachment);
|
||||
await _dbContext.SaveChangesAsync();
|
||||
return Ok();
|
||||
}
|
||||
[HttpGet]
|
||||
[Authorize("read:orders")]
|
||||
[Route("/api/Orders/{orderId:int}/Message/{messageId:int}/Attachment")]
|
||||
public async Task<IActionResult> MessageAttachments(int orderId, int messageId)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var order = await _dbContext.SellerServiceOrders
|
||||
.Include(x=>x.Messages)
|
||||
.Include(x=>x.Seller)
|
||||
.Include(x=>x.SellerService)
|
||||
.FirstOrDefaultAsync(x=>x.Id==orderId);
|
||||
if(order==null)
|
||||
return NotFound("/Order not found.");
|
||||
if(order.BuyerId!=userId && order.Seller.UserId!=userId)
|
||||
return BadRequest("You are not the buyer or seller of this order.");
|
||||
if(order.Status==EnumOrderStatus.Completed || order.Status==EnumOrderStatus.Cancelled)
|
||||
return BadRequest("/Order is already complete.");
|
||||
if(order.Status<EnumOrderStatus.Waitlist)
|
||||
return BadRequest("/Order is not accepted.");
|
||||
|
||||
var message = _dbContext.SellerServiceOrderMessages.Include(x=>x.Attachments)
|
||||
.First(x=>x.Id==messageId && x.SellerServiceOrderId==orderId);
|
||||
if(message==null)
|
||||
return BadRequest("Message does not exist or does not belong to this order.");
|
||||
|
||||
var content = await _storageService.DownloadImageAsync(message.Attachments.First().FileReference);
|
||||
return new FileStreamResult(content, "application/octet-stream");
|
||||
}
|
||||
}
|
||||
|
346
src/comissions.app.api/Controllers/SellerOrderController.cs
Normal file
346
src/comissions.app.api/Controllers/SellerOrderController.cs
Normal file
@ -0,0 +1,346 @@
|
||||
using comissions.app.api.Extensions;
|
||||
using comissions.app.api.Models.Order;
|
||||
using ArtPlatform.Database;
|
||||
using ArtPlatform.Database.Entities;
|
||||
using comissions.app.api.Services.Storage;
|
||||
using comissions.app.database;
|
||||
using comissions.app.database.Entities;
|
||||
using comissions.app.database.Enums;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace comissions.app.api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class SellerOrderController : Controller
|
||||
{
|
||||
private readonly ApplicationDbContext _dbContext;
|
||||
private readonly IStorageService _storageService;
|
||||
|
||||
public SellerOrderController(IStorageService storageService, ApplicationDbContext dbContext)
|
||||
{
|
||||
_storageService = storageService;
|
||||
_dbContext = dbContext;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route("/api/SellerOrders")]
|
||||
[Authorize("read:seller-orders")]
|
||||
public async Task<IActionResult> GetOrders(int offset = 0, int pageSize = 10, EnumOrderStatus? status = null)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var orders = await _dbContext.SellerServiceOrders
|
||||
.Include(x=>x.Seller)
|
||||
.Where(x => x.Seller.UserId == userId && status==null ? true : status==x.Status)
|
||||
.Skip(offset).Take(pageSize).ToListAsync();
|
||||
|
||||
var result = orders.Select(x => x.ToModel()).ToList();
|
||||
return Ok(result);
|
||||
}
|
||||
[HttpGet]
|
||||
[Route("/api/SellerOrders/{orderId:int}")]
|
||||
[Authorize("read:seller-orders")]
|
||||
public async Task<IActionResult> GetOrder(int orderId, int offset = 0, int pageSize = 10, EnumOrderStatus? status = null)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var order = await _dbContext.SellerServiceOrders
|
||||
.Include(x => x.Seller)
|
||||
.FirstAsync(x => x.Id==orderId && x.Seller.UserId == userId && status == null ? true : status == x.Status);
|
||||
var result = order.ToModel();
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[Authorize("write:seller-orders")]
|
||||
[Route("/api/SellerOrders/{orderId:int}/Cancel")]
|
||||
public async Task<IActionResult> CancelOrder(int orderId)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var seller = await _dbContext.UserSellerProfiles.FirstOrDefaultAsync(x=>x.UserId==userId);
|
||||
if(seller==null)
|
||||
return NotFound("User it not a seller.");
|
||||
if(seller.Suspended)
|
||||
return BadRequest("Seller is suspended.");
|
||||
var order = await _dbContext.SellerServiceOrders
|
||||
.Include(x=>x.SellerService)
|
||||
.FirstOrDefaultAsync(x=>x.Id==orderId && x.Seller.UserId==userId);
|
||||
if(order==null)
|
||||
return NotFound("Order not found.");
|
||||
if(order.Status==EnumOrderStatus.Completed || order.Status== EnumOrderStatus.Cancelled)
|
||||
return BadRequest("Order is already complete.");
|
||||
if(order.BuyerId!=userId)
|
||||
return BadRequest("You are not the buyer of this order.");
|
||||
if(order.Status!=EnumOrderStatus.Completed && order.Status!= EnumOrderStatus.Cancelled)
|
||||
return BadRequest("Order is not in a cancellable state.");
|
||||
order.Status = EnumOrderStatus.Cancelled;
|
||||
order.EndDate = DateTime.UtcNow;
|
||||
order = _dbContext.SellerServiceOrders.Update(order).Entity;
|
||||
await _dbContext.SaveChangesAsync();
|
||||
var result = order.ToModel();
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPut]
|
||||
[Authorize("write:seller-orders")]
|
||||
[Route("/api/SellerOrders/{orderId:int}/Accept")]
|
||||
public async Task<IActionResult> AcceptOrder(int orderId)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var seller = await _dbContext.UserSellerProfiles.FirstOrDefaultAsync(x=>x.UserId==userId);
|
||||
if(seller==null)
|
||||
return NotFound("User it not a seller.");
|
||||
if(seller.Suspended)
|
||||
return BadRequest("Seller is suspended.");
|
||||
var order = await _dbContext.SellerServiceOrders
|
||||
.Include(x=>x.SellerService)
|
||||
.FirstOrDefaultAsync(x=>x.Id==orderId && x.Seller.UserId==userId);
|
||||
if(order==null)
|
||||
return NotFound("Order not found.");
|
||||
if(order.Status==EnumOrderStatus.Completed || order.Status== EnumOrderStatus.Cancelled)
|
||||
return BadRequest("Order is already complete.");
|
||||
if(order.BuyerId!=userId)
|
||||
return BadRequest("You are not the buyer of this order.");
|
||||
if(order.Status!=EnumOrderStatus.PendingAcceptance)
|
||||
return BadRequest("Order has already been accepted.");
|
||||
order.Status = EnumOrderStatus.Waitlist;
|
||||
order = _dbContext.SellerServiceOrders.Update(order).Entity;
|
||||
await _dbContext.SaveChangesAsync();
|
||||
var result = order.ToModel();
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPut]
|
||||
[Authorize("write:seller-orders")]
|
||||
[Route("/api/SellerOrders/{orderId:int}/Start")]
|
||||
public async Task<IActionResult> StartOrder(int orderId)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var seller = await _dbContext.UserSellerProfiles.FirstOrDefaultAsync(x=>x.UserId==userId);
|
||||
if(seller==null)
|
||||
return NotFound("User it not a seller.");
|
||||
if(seller.Suspended)
|
||||
return BadRequest("Seller is suspended.");
|
||||
var order = await _dbContext.SellerServiceOrders
|
||||
.Include(x=>x.SellerService)
|
||||
.FirstOrDefaultAsync(x=>x.Id==orderId && x.Seller.UserId==userId);
|
||||
if(order==null)
|
||||
return NotFound("Order not found.");
|
||||
if(order.Status==EnumOrderStatus.Completed || order.Status== EnumOrderStatus.Cancelled)
|
||||
return BadRequest("Order is already complete.");
|
||||
if(order.BuyerId!=userId)
|
||||
return BadRequest("You are not the buyer of this order.");
|
||||
if(order.Status!=EnumOrderStatus.Waitlist)
|
||||
return BadRequest("Order has already been started.");
|
||||
order.Status = EnumOrderStatus.DiscussingRequirements;
|
||||
order = _dbContext.SellerServiceOrders.Update(order).Entity;
|
||||
await _dbContext.SaveChangesAsync();
|
||||
var result = order.ToModel();
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPut]
|
||||
[Authorize("write:seller-orders")]
|
||||
[Route("/api/SellerOrders/{orderId:int}/AdjustPrice")]
|
||||
public async Task<IActionResult> AdjustPrice(int orderId,[FromQuery]double price)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var seller = await _dbContext.UserSellerProfiles.FirstOrDefaultAsync(x=>x.UserId==userId);
|
||||
if(seller==null)
|
||||
return NotFound("User it not a seller.");
|
||||
if(seller.Suspended)
|
||||
return BadRequest("Seller is suspended.");
|
||||
|
||||
var order = await _dbContext.SellerServiceOrders
|
||||
.Include(x=>x.Seller)
|
||||
.Include(x=>x.SellerService)
|
||||
.FirstOrDefaultAsync(x=>x.Id==orderId && x.Seller.UserId==userId);
|
||||
if(order==null)
|
||||
return NotFound("Order not found.");
|
||||
if(order.Seller.UserId!=userId)
|
||||
return BadRequest("You are not the seller of this order.");
|
||||
if(order.Status==EnumOrderStatus.Completed || order.Status== EnumOrderStatus.Cancelled)
|
||||
return BadRequest("Order is already complete.");
|
||||
if(order.Status>EnumOrderStatus.DiscussingRequirements)
|
||||
return BadRequest("Order requirements and price have already been confirmed.");
|
||||
if(order.Status<EnumOrderStatus.DiscussingRequirements)
|
||||
return BadRequest("Order has not been started.");
|
||||
order.Price = price;
|
||||
order = _dbContext.SellerServiceOrders.Update(order).Entity;
|
||||
await _dbContext.SaveChangesAsync();
|
||||
var result = order.ToModel();
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPut]
|
||||
[Authorize("write:seller-orders")]
|
||||
[Route("/api/SellerOrders/{orderId:int}/CompleteRevision")]
|
||||
public async Task<IActionResult> CompleteRevision(int orderId)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var order = await _dbContext.SellerServiceOrders
|
||||
.Include(x=>x.Seller)
|
||||
.Include(x=>x.SellerService)
|
||||
.FirstOrDefaultAsync(x=>x.Id==orderId && x.Seller.UserId==userId);
|
||||
var seller = await _dbContext.UserSellerProfiles.FirstOrDefaultAsync(x=>x.UserId==userId);
|
||||
if(seller==null)
|
||||
return NotFound("User it not a seller.");
|
||||
if(seller.Suspended)
|
||||
return BadRequest("Seller is suspended.");
|
||||
if(order==null)
|
||||
return NotFound("Order not found.");
|
||||
if(order.Seller.UserId!=userId)
|
||||
return BadRequest("You are not the seller of this order.");
|
||||
if(order.Status==EnumOrderStatus.Completed || order.Status== EnumOrderStatus.Cancelled)
|
||||
return BadRequest("Order is already complete.");
|
||||
if(order.Status<EnumOrderStatus.InProgress)
|
||||
return BadRequest("Order has not been started.");
|
||||
if(order.Status>EnumOrderStatus.InProgress)
|
||||
return BadRequest("Order is pending review already.");
|
||||
order.Status = EnumOrderStatus.PendingReview;
|
||||
order = _dbContext.SellerServiceOrders.Update(order).Entity;
|
||||
await _dbContext.SaveChangesAsync();
|
||||
var result = order.ToModel();
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Authorize("read:orders")]
|
||||
[Route("/api/SellerOrders/{orderId:int}/Messages")]
|
||||
public async Task<IActionResult> GetMessages(int orderId, int offset = 0, int pageSize = 10)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var order = await _dbContext.SellerServiceOrders
|
||||
.Include(x=>x.Seller)
|
||||
.FirstOrDefaultAsync(x=>x.Id==orderId && x.Seller.UserId==userId);
|
||||
var seller = await _dbContext.UserSellerProfiles.FirstOrDefaultAsync(x=>x.UserId==userId);
|
||||
if(seller==null)
|
||||
return NotFound("User it not a seller.");
|
||||
if(seller.Suspended)
|
||||
return BadRequest("Seller is suspended.");
|
||||
if(order==null)
|
||||
return NotFound("Order not found.");
|
||||
if(order.BuyerId!=userId && order.Seller.UserId!=userId)
|
||||
return BadRequest("You are not the buyer or seller of this order.");
|
||||
var messages = _dbContext.SellerServiceOrderMessages
|
||||
.Include(x=>x.Sender)
|
||||
.Include(x=>x.Attachments)
|
||||
.OrderBy(x=>x.SentAt)
|
||||
.Where(x=>x.SellerServiceOrderId==orderId)
|
||||
.Skip(offset).Take(pageSize).ToList();
|
||||
var result = messages.Select(x=>x.ToModel()).ToList();
|
||||
return Ok(result);
|
||||
}
|
||||
[HttpPost]
|
||||
[Authorize("write:orders")]
|
||||
[Route("/api/SellerOrders/{orderId:int}/Message")]
|
||||
public async Task<IActionResult> Message(int orderId, [FromBody] SellerServiceOrderMessageModel model)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var seller = await _dbContext.UserSellerProfiles.FirstOrDefaultAsync(x=>x.UserId==userId);
|
||||
if(seller==null)
|
||||
return NotFound("User it not a seller.");
|
||||
if(seller.Suspended)
|
||||
return BadRequest("Seller is suspended.");
|
||||
var order = await _dbContext.SellerServiceOrders
|
||||
.Include(x=>x.Messages)
|
||||
.Include(x=>x.Seller)
|
||||
.Include(x=>x.SellerService)
|
||||
.FirstOrDefaultAsync(x=>x.Id==orderId && x.Seller.UserId==userId);
|
||||
if(order==null)
|
||||
return NotFound("Order not found.");
|
||||
if(order.Status==EnumOrderStatus.Completed || order.Status==EnumOrderStatus.Cancelled)
|
||||
return BadRequest("Order is already complete.");
|
||||
if(order.BuyerId!=userId && order.Seller.UserId!=userId)
|
||||
return BadRequest("You are not the buyer or seller of this order.");
|
||||
if(order.Status<EnumOrderStatus.Waitlist)
|
||||
return BadRequest("Order is not accepted.");
|
||||
var message = new SellerServiceOrderMessage()
|
||||
{
|
||||
SellerServiceOrderId = orderId,
|
||||
Message = model.Message,
|
||||
SentAt = DateTime.UtcNow,
|
||||
SenderId = userId,
|
||||
Sender = await _dbContext.Users.FirstOrDefaultAsync(x=>x.Id==userId),
|
||||
};
|
||||
var dbMessage = _dbContext.SellerServiceOrderMessages.Add(message).Entity;
|
||||
await _dbContext.SaveChangesAsync();
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Authorize("write:orders")]
|
||||
[Route("/api/SellerOrders/{orderId:int}/Message/{messageId:int}/Attachment")]
|
||||
public async Task<IActionResult> MessageAttachment(int orderId, int messageId,IFormFile file)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var seller = await _dbContext.UserSellerProfiles.FirstOrDefaultAsync(x=>x.UserId==userId);
|
||||
if(seller==null)
|
||||
return NotFound("User it not a seller.");
|
||||
if(seller.Suspended)
|
||||
return BadRequest("Seller is suspended.");
|
||||
var order = await _dbContext.SellerServiceOrders
|
||||
.Include(x=>x.Messages)
|
||||
.Include(x=>x.Seller)
|
||||
.Include(x=>x.SellerService)
|
||||
.FirstOrDefaultAsync(x=>x.Id==orderId && x.Seller.UserId==userId);
|
||||
if(order==null)
|
||||
return NotFound("Order not found.");
|
||||
if(order.BuyerId!=userId && order.Seller.UserId!=userId)
|
||||
return BadRequest("You are not the buyer or seller of this order.");
|
||||
if(order.Status==EnumOrderStatus.Completed || order.Status==EnumOrderStatus.Cancelled)
|
||||
return BadRequest("Order is already complete.");
|
||||
if(order.Status<EnumOrderStatus.Waitlist)
|
||||
return BadRequest("Order is not accepted.");
|
||||
|
||||
var message = _dbContext.SellerServiceOrderMessages.First(x=>x.Id==messageId && x.SellerServiceOrderId==orderId);
|
||||
if(message==null)
|
||||
return BadRequest("Message does not exist or does not belong to this order.");
|
||||
|
||||
var url = await _storageService.UploadImageAsync(file, Guid.NewGuid().ToString());
|
||||
var attachment = new SellerServiceOrderMessageAttachment()
|
||||
{
|
||||
SellerServiceOrderMessageId = message.Id,
|
||||
FileReference = url
|
||||
};
|
||||
_dbContext.SellerServiceOrderMessageAttachments.Add(attachment);
|
||||
await _dbContext.SaveChangesAsync();
|
||||
return Ok();
|
||||
}
|
||||
[HttpGet]
|
||||
[Authorize("read:orders")]
|
||||
[Route("/api/SellerOrders/{orderId:int}/Message/{messageId:int}/Attachment")]
|
||||
public async Task<IActionResult> MessageAttachments(int orderId, int messageId)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var seller = await _dbContext.UserSellerProfiles.FirstOrDefaultAsync(x=>x.UserId==userId);
|
||||
if(seller==null)
|
||||
return NotFound("User it not a seller.");
|
||||
if(seller.Suspended)
|
||||
return BadRequest("Seller is suspended.");
|
||||
var order = await _dbContext.SellerServiceOrders
|
||||
.Include(x=>x.Messages)
|
||||
.Include(x=>x.Seller)
|
||||
.Include(x=>x.SellerService)
|
||||
.FirstOrDefaultAsync(x=>x.Id==orderId);
|
||||
if(order==null)
|
||||
return NotFound("Order not found.");
|
||||
if(order.BuyerId!=userId && order.Seller.UserId!=userId)
|
||||
return BadRequest("You are not the buyer or seller of this order.");
|
||||
if(order.Status==EnumOrderStatus.Completed || order.Status==EnumOrderStatus.Cancelled)
|
||||
return BadRequest("Order is already complete.");
|
||||
if(order.Status<EnumOrderStatus.Waitlist)
|
||||
return BadRequest("Order is not accepted.");
|
||||
|
||||
var message = _dbContext.SellerServiceOrderMessages.Include(x=>x.Attachments)
|
||||
.First(x=>x.Id==messageId && x.SellerServiceOrderId==orderId);
|
||||
if(message==null)
|
||||
return BadRequest("Message does not exist or does not belong to this order.");
|
||||
var attachment = message.Attachments.FirstOrDefault();
|
||||
if(attachment==null)
|
||||
return BadRequest("Message does not have an attachment.");
|
||||
var content = await _storageService.DownloadImageAsync(message.Attachments.First().FileReference);
|
||||
return new FileStreamResult(content, "application/octet-stream");
|
||||
}
|
||||
}
|
246
src/comissions.app.api/Controllers/SellerProfileController.cs
Normal file
246
src/comissions.app.api/Controllers/SellerProfileController.cs
Normal file
@ -0,0 +1,246 @@
|
||||
using comissions.app.api.Extensions;
|
||||
using comissions.app.api.Models.PortfolioModel;
|
||||
using ArtPlatform.Database;
|
||||
using ArtPlatform.Database.Entities;
|
||||
using comissions.app.api.Models.SellerProfile;
|
||||
using comissions.app.api.Services.Payment;
|
||||
using comissions.app.api.Services.Storage;
|
||||
using comissions.app.database;
|
||||
using comissions.app.database.Entities;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace comissions.app.api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class SellerProfileController : Controller
|
||||
{
|
||||
private readonly ApplicationDbContext _dbContext;
|
||||
private readonly IStorageService _storageService;
|
||||
private readonly IPaymentService _paymentService;
|
||||
|
||||
|
||||
public SellerProfileController(ApplicationDbContext dbContext, IPaymentService paymentService, IStorageService storageService)
|
||||
{
|
||||
_paymentService = paymentService;
|
||||
_storageService = storageService;
|
||||
_dbContext = dbContext;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Authorize("read:seller-profile")]
|
||||
public async Task<IActionResult> GetSellerProfile()
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var sellerProfile = await _dbContext.UserSellerProfiles.FirstOrDefaultAsync(sellerProfile=>sellerProfile.UserId==userId);
|
||||
if(sellerProfile==null)
|
||||
{
|
||||
var sellerProfileRequest = await _dbContext.SellerProfileRequests.FirstOrDefaultAsync(request=>request.UserId==userId && request.Accepted==false);
|
||||
if(sellerProfileRequest!=null)
|
||||
return BadRequest("Account has requested to be a seller and not been approved yet.");
|
||||
return Unauthorized("Account is not a seller.");
|
||||
}
|
||||
var result = sellerProfile.ToModel();
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPut]
|
||||
[Authorize("write:seller-profile")]
|
||||
public async Task<IActionResult> UpdateSellerProfile(SellerProfileModel model)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var existingSellerProfile = await _dbContext.UserSellerProfiles.FirstOrDefaultAsync(sellerProfile=>sellerProfile.UserId==userId);
|
||||
if (existingSellerProfile == null)
|
||||
{
|
||||
var sellerProfileRequest = await _dbContext.SellerProfileRequests.FirstOrDefaultAsync(request=>request.UserId==userId && request.Accepted==false);
|
||||
if(sellerProfileRequest!=null)
|
||||
return BadRequest("Account has requested to be a seller and not been approved yet.");
|
||||
return Unauthorized("Account is not a seller.");
|
||||
}
|
||||
var updatedSellerProfile = model.ToModel(existingSellerProfile);
|
||||
updatedSellerProfile = _dbContext.UserSellerProfiles.Update(updatedSellerProfile).Entity;
|
||||
await _dbContext.SaveChangesAsync();
|
||||
var result = updatedSellerProfile.ToModel();
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Authorize("write:seller-profile")]
|
||||
public async Task<IActionResult> RequestSellerProfile(SellerProfileModel model)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
|
||||
var existingSellerProfile = await _dbContext.UserSellerProfiles.FirstOrDefaultAsync(sellerProfile=>sellerProfile.UserId==userId);
|
||||
if (existingSellerProfile != null)
|
||||
{
|
||||
return Unauthorized("Account is already a seller.");
|
||||
}
|
||||
|
||||
var sellerProfileRequest = await _dbContext.SellerProfileRequests.FirstOrDefaultAsync(request=>request.UserId==userId);
|
||||
if(sellerProfileRequest!=null)
|
||||
return BadRequest("Account has already requested to be a seller.");
|
||||
|
||||
sellerProfileRequest = new SellerProfileRequest()
|
||||
{
|
||||
Accepted = false,
|
||||
RequestDate = DateTime.UtcNow,
|
||||
UserId = userId
|
||||
};
|
||||
_dbContext.SellerProfileRequests.Add(sellerProfileRequest);
|
||||
await _dbContext.SaveChangesAsync();
|
||||
return Ok();
|
||||
}
|
||||
[HttpGet]
|
||||
[Authorize("read:seller-profile")]
|
||||
[Route("{sellerServiceId:int}/Portfolio/{portfolioId:int}")]
|
||||
public async Task<IActionResult> GetPortfolio(int sellerServiceId, int portfolioId)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var existingSellerProfile = await _dbContext.UserSellerProfiles.FirstOrDefaultAsync(sellerProfile=>sellerProfile.UserId==userId);
|
||||
if (existingSellerProfile == null)
|
||||
{
|
||||
var sellerProfileRequest = await _dbContext.SellerProfileRequests.FirstOrDefaultAsync(request=>request.UserId==userId && request.Accepted==false);
|
||||
if(sellerProfileRequest!=null)
|
||||
return BadRequest("Account has requested to be a seller and not been approved yet.");
|
||||
return Unauthorized("Account is not a seller.");
|
||||
}
|
||||
if(existingSellerProfile.Suspended)
|
||||
return BadRequest("Seller is suspended.");
|
||||
|
||||
var portfolio = await _dbContext.SellerProfilePortfolioPieces
|
||||
.FirstAsync(x => x.SellerProfileId == existingSellerProfile.Id && x.Id==portfolioId);
|
||||
var content = await _storageService.DownloadImageAsync(portfolio.FileReference);
|
||||
return new FileStreamResult(content, "application/octet-stream");
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route("Portfolio")]
|
||||
[Authorize("read:seller-profile")]
|
||||
public async Task<IActionResult> GetPortfolio()
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var existingSellerProfile = await _dbContext.UserSellerProfiles.FirstOrDefaultAsync(sellerProfile=>sellerProfile.UserId==userId);
|
||||
if (existingSellerProfile == null)
|
||||
{
|
||||
var sellerProfileRequest = await _dbContext.SellerProfileRequests.FirstOrDefaultAsync(request=>request.UserId==userId && request.Accepted==false);
|
||||
if(sellerProfileRequest!=null)
|
||||
return BadRequest("Account has requested to be a seller and not been approved yet.");
|
||||
return Unauthorized("Account is not a seller.");
|
||||
}
|
||||
if(existingSellerProfile.Suspended)
|
||||
return BadRequest("Seller is suspended.");
|
||||
var portfolio = await _dbContext.SellerProfilePortfolioPieces.Where(x=>x.SellerProfileId==existingSellerProfile.Id).ToListAsync();
|
||||
var result = portfolio.Select(x=>x.ToModel()).ToList();
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Route("Portfolio")]
|
||||
[Authorize("write:seller-profile")]
|
||||
public async Task<IActionResult> AddPortfolio(IFormFile file)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var existingSellerProfile = await _dbContext.UserSellerProfiles.FirstOrDefaultAsync(sellerProfile=>sellerProfile.UserId==userId);
|
||||
if (existingSellerProfile == null)
|
||||
{
|
||||
var sellerProfileRequest = await _dbContext.SellerProfileRequests.FirstOrDefaultAsync(request=>request.UserId==userId && request.Accepted==false);
|
||||
if(sellerProfileRequest!=null)
|
||||
return BadRequest("Account has requested to be a seller and not been approved yet.");
|
||||
return Unauthorized("Account is not a seller.");
|
||||
}
|
||||
|
||||
if(existingSellerProfile.Suspended)
|
||||
return BadRequest("Seller is suspended.");
|
||||
var url = await _storageService.UploadImageAsync(file, Guid.NewGuid().ToString());
|
||||
var portfolio = new SellerProfilePortfolioPiece()
|
||||
{
|
||||
SellerProfileId = existingSellerProfile.Id,
|
||||
FileReference = url
|
||||
};
|
||||
portfolio.SellerProfileId = existingSellerProfile.Id;
|
||||
_dbContext.SellerProfilePortfolioPieces.Add(portfolio);
|
||||
await _dbContext.SaveChangesAsync();
|
||||
var result = portfolio.ToModel();
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[Authorize("write:seller-profile")]
|
||||
[Route("Portfolio/{portfolioId:int}")]
|
||||
public async Task<IActionResult> DeletePortfolio(int portfolioId)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var existingSellerProfile = await _dbContext.UserSellerProfiles.FirstOrDefaultAsync(sellerProfile=>sellerProfile.UserId==userId);
|
||||
if (existingSellerProfile == null)
|
||||
{
|
||||
var sellerProfileRequest = await _dbContext.SellerProfileRequests.FirstOrDefaultAsync(request=>request.UserId==userId && request.Accepted==false);
|
||||
if(sellerProfileRequest!=null)
|
||||
return BadRequest("Account has requested to be a seller and not been approved yet.");
|
||||
return Unauthorized("Account is not a seller.");
|
||||
}
|
||||
if(existingSellerProfile.Suspended)
|
||||
return BadRequest("Seller is suspended.");
|
||||
var portfolio = await _dbContext.SellerProfilePortfolioPieces.FirstOrDefaultAsync(x=>x.Id==portfolioId);
|
||||
if(portfolio==null)
|
||||
return NotFound("Portfolio piece not found.");
|
||||
if(portfolio.SellerProfileId!=existingSellerProfile.Id)
|
||||
return BadRequest("Portfolio piece does not belong to this seller.");
|
||||
_dbContext.SellerProfilePortfolioPieces.Remove(portfolio);
|
||||
await _dbContext.SaveChangesAsync();
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Authorize("write:seller-profile")]
|
||||
[Route("Payment")]
|
||||
public async Task<IActionResult> CreatePaymentAccount()
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var existingSellerProfile = await _dbContext.UserSellerProfiles.FirstOrDefaultAsync(sellerProfile=>sellerProfile.UserId==userId);
|
||||
if (existingSellerProfile == null)
|
||||
{
|
||||
var sellerProfileRequest = await _dbContext.SellerProfileRequests.FirstOrDefaultAsync(request=>request.UserId==userId && request.Accepted==false);
|
||||
if(sellerProfileRequest!=null)
|
||||
return BadRequest("Account has requested to be a seller and not been approved yet.");
|
||||
return Unauthorized("Account is not a seller.");
|
||||
}
|
||||
|
||||
if(existingSellerProfile.Suspended)
|
||||
return BadRequest("Seller is suspended.");
|
||||
if(existingSellerProfile.StripeAccountId!=null)
|
||||
return BadRequest("Account already have a payment account.");
|
||||
|
||||
var accountId = _paymentService.CreateSellerAccount();
|
||||
existingSellerProfile.StripeAccountId = accountId;
|
||||
existingSellerProfile = _dbContext.UserSellerProfiles.Update(existingSellerProfile).Entity;
|
||||
await _dbContext.SaveChangesAsync();
|
||||
var result = existingSellerProfile.ToModel();
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Authorize("write:seller-profile")]
|
||||
[Route("Payment")]
|
||||
public async Task<IActionResult> GetPaymentAccount()
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var existingSellerProfile = await _dbContext.UserSellerProfiles.FirstOrDefaultAsync(sellerProfile=>sellerProfile.UserId==userId);
|
||||
if (existingSellerProfile == null)
|
||||
{
|
||||
var sellerProfileRequest = await _dbContext.SellerProfileRequests.FirstOrDefaultAsync(request=>request.UserId==userId && request.Accepted==false);
|
||||
if(sellerProfileRequest!=null)
|
||||
return BadRequest("Account has requested to be a seller and not been approved yet.");
|
||||
return Unauthorized("Account is not a seller.");
|
||||
}
|
||||
if(existingSellerProfile.Suspended)
|
||||
return BadRequest("Seller is suspended.");
|
||||
if(existingSellerProfile.StripeAccountId==null)
|
||||
return BadRequest("Account does not have a payment account.");
|
||||
|
||||
var result = _paymentService.CreateSellerAccountOnboardingUrl(existingSellerProfile.StripeAccountId);
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
}
|
261
src/comissions.app.api/Controllers/SellerServiceController.cs
Normal file
261
src/comissions.app.api/Controllers/SellerServiceController.cs
Normal file
@ -0,0 +1,261 @@
|
||||
using comissions.app.api.Extensions;
|
||||
using comissions.app.api.Models.PortfolioModel;
|
||||
using ArtPlatform.Database;
|
||||
using ArtPlatform.Database.Entities;
|
||||
using comissions.app.api.Models.SellerService;
|
||||
using comissions.app.api.Services.Payment;
|
||||
using comissions.app.api.Services.Storage;
|
||||
using comissions.app.database;
|
||||
using comissions.app.database.Entities;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace comissions.app.api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class SellerServiceController : Controller
|
||||
{
|
||||
private readonly ApplicationDbContext _dbContext;
|
||||
private readonly IStorageService _storageService;
|
||||
private readonly IPaymentService _paymentService;
|
||||
|
||||
public SellerServiceController(ApplicationDbContext dbContext, IPaymentService paymentService, IStorageService storageService)
|
||||
{
|
||||
_paymentService = paymentService;
|
||||
_storageService = storageService;
|
||||
_dbContext = dbContext;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Authorize("read:seller-service")]
|
||||
public async Task<IActionResult> GetSellerServices(int offset=0, int pageSize=10)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var seller = await _dbContext.UserSellerProfiles.FirstOrDefaultAsync(sellerProfile=>sellerProfile.UserId==userId);
|
||||
|
||||
if(seller==null)
|
||||
return BadRequest("Account is not a seller.");
|
||||
|
||||
if(seller.Suspended)
|
||||
return BadRequest("Seller is suspended.");
|
||||
|
||||
var sellerServices = await _dbContext.SellerServices.Where(x=>x.Archived==false).Include(x=>x.Reviews)
|
||||
.Skip(offset).Take(pageSize).ToListAsync();
|
||||
var result = sellerServices.Select(x=>x.ToModel()).ToList();
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route("Count")]
|
||||
[Authorize("read:seller-service")]
|
||||
public async Task<IActionResult> GetSellerServicesCount()
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var seller = await _dbContext.UserSellerProfiles.FirstOrDefaultAsync(sellerProfile=>sellerProfile.UserId==userId);
|
||||
|
||||
if(seller==null)
|
||||
return BadRequest("Account is not a seller.");
|
||||
|
||||
if(seller.Suspended)
|
||||
return BadRequest("Seller is suspended.");
|
||||
|
||||
var sellerServices = await _dbContext.SellerServices.Where(x=>x.Archived==false).Include(x => x.Reviews).ToListAsync();
|
||||
var result = sellerServices.Count;
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Authorize("write:seller-service")]
|
||||
public async Task<IActionResult> CreateSellerService([FromBody] SellerServiceCreateModel model)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var seller = await _dbContext.UserSellerProfiles.FirstOrDefaultAsync(sellerProfile=>sellerProfile.UserId==userId);
|
||||
|
||||
if(seller==null)
|
||||
return BadRequest("Account is not a seller.");
|
||||
|
||||
if(seller.Suspended)
|
||||
return BadRequest("Seller is suspended.");
|
||||
|
||||
if(seller.StripeAccountId==null)
|
||||
return BadRequest("Account does not have a payment account.");
|
||||
|
||||
if (_paymentService.SellerAccountIsOnboarded(seller.StripeAccountId) == false)
|
||||
return BadRequest("Account has not finished onboarding.");
|
||||
|
||||
var sellerService = new SellerService()
|
||||
{
|
||||
Name = model.Name,
|
||||
Description = model.Description,
|
||||
Price = model.Price,
|
||||
SellerProfileId = seller.Id
|
||||
};
|
||||
sellerService = _dbContext.SellerServices.Add(sellerService).Entity;
|
||||
await _dbContext.SaveChangesAsync();
|
||||
var result = sellerService.ToModel();
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPut]
|
||||
[Authorize("write:seller-service")]
|
||||
[Route("{sellerServiceId:int}")]
|
||||
public async Task<IActionResult> UpdateSellerService([FromBody] SellerServiceUpdateModel model, int sellerServiceId)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var seller = await _dbContext.UserSellerProfiles.FirstOrDefaultAsync(sellerProfile=>sellerProfile.UserId==userId);
|
||||
|
||||
if(seller==null)
|
||||
return BadRequest("Account is not a seller.");
|
||||
|
||||
if(seller.Suspended)
|
||||
return BadRequest("Seller is suspended.");
|
||||
|
||||
var sellerService = await _dbContext.SellerServices.FirstOrDefaultAsync(sellerService=>sellerService.Id==sellerServiceId);
|
||||
|
||||
if(sellerService==null)
|
||||
return NotFound("Seller service not found.");
|
||||
|
||||
sellerService.Name = model.Name;
|
||||
sellerService.Description = model.Description;
|
||||
sellerService.Price = model.Price;
|
||||
|
||||
sellerService = _dbContext.SellerServices.Update(sellerService).Entity;
|
||||
await _dbContext.SaveChangesAsync();
|
||||
var result = sellerService.ToModel();
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[Authorize("write:seller-service")]
|
||||
[Route("{sellerServiceId:int}")]
|
||||
public async Task<IActionResult> DeleteSellerService(int sellerServiceId)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var seller = await _dbContext.UserSellerProfiles.FirstOrDefaultAsync(sellerProfile=>sellerProfile.UserId==userId);
|
||||
|
||||
if(seller==null)
|
||||
return BadRequest("Account is not a seller.");
|
||||
|
||||
if(seller.Suspended)
|
||||
return BadRequest("Seller is suspended.");
|
||||
|
||||
var sellerService = await _dbContext.SellerServices.FirstOrDefaultAsync(sellerService=>sellerService.Id==sellerServiceId);
|
||||
|
||||
if(sellerService==null)
|
||||
return NotFound("Seller service not found.");
|
||||
|
||||
sellerService.Archived = true;
|
||||
_dbContext.SellerServices.Update(sellerService);
|
||||
await _dbContext.SaveChangesAsync();
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route("{sellerServiceId:int}/Portfolio/")]
|
||||
public async Task<IActionResult> GetPortfolio(int sellerServiceId)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var existingSellerProfile = await _dbContext.UserSellerProfiles.FirstOrDefaultAsync(sellerProfile=>sellerProfile.UserId==userId);
|
||||
|
||||
|
||||
if (existingSellerProfile == null)
|
||||
{
|
||||
var sellerProfileRequest = await _dbContext.SellerProfileRequests.FirstOrDefaultAsync(request=>request.UserId==userId && request.Accepted==false);
|
||||
if(sellerProfileRequest!=null)
|
||||
return BadRequest("Account has requested to be a seller and not been approved yet.");
|
||||
return Unauthorized("Account is not a seller.");
|
||||
}
|
||||
if(existingSellerProfile.Suspended)
|
||||
return BadRequest("Seller is suspended.");
|
||||
var portfolio = await _dbContext.SellerProfilePortfolioPieces.Where(x=>x.SellerProfileId==existingSellerProfile.Id && x.SellerServiceId==sellerServiceId).ToListAsync();
|
||||
var result = portfolio.Select(x=>x.ToModel()).ToList();
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
|
||||
[HttpGet]
|
||||
[Authorize("read:seller-service")]
|
||||
[Route("{sellerServiceId:int}/Portfolio/{portfolioId:int}")]
|
||||
public async Task<IActionResult> GetPortfolio(int sellerServiceId, int portfolioId)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var existingSellerProfile = await _dbContext.UserSellerProfiles.FirstOrDefaultAsync(sellerProfile=>sellerProfile.UserId==userId);
|
||||
if (existingSellerProfile == null)
|
||||
{
|
||||
var sellerProfileRequest = await _dbContext.SellerProfileRequests.FirstOrDefaultAsync(request=>request.UserId==userId && request.Accepted==false);
|
||||
if(sellerProfileRequest!=null)
|
||||
return BadRequest("Account has requested to be a seller and not been approved yet.");
|
||||
return Unauthorized("Account is not a seller.");
|
||||
}
|
||||
|
||||
if(existingSellerProfile.Suspended)
|
||||
return BadRequest("Seller is suspended.");
|
||||
|
||||
var portfolio = await _dbContext.SellerProfilePortfolioPieces
|
||||
.FirstAsync(x => x.SellerProfileId == existingSellerProfile.Id
|
||||
&& x.SellerServiceId == sellerServiceId && x.Id==portfolioId);
|
||||
var content = await _storageService.DownloadImageAsync(portfolio.FileReference);
|
||||
return new FileStreamResult(content, "application/octet-stream");
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Authorize("write:seller-service")]
|
||||
[Route("{sellerServiceId:int}/Portfolio")]
|
||||
public async Task<IActionResult> AddPortfolio(IFormFile file, int sellerServiceId)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var existingSellerProfile = await _dbContext.UserSellerProfiles.FirstOrDefaultAsync(sellerProfile=>sellerProfile.UserId==userId);
|
||||
if (existingSellerProfile == null)
|
||||
{
|
||||
var sellerProfileRequest = await _dbContext.SellerProfileRequests.FirstOrDefaultAsync(request=>request.UserId==userId && request.Accepted==false);
|
||||
if(sellerProfileRequest!=null)
|
||||
return BadRequest("Account has requested to be a seller and not been approved yet.");
|
||||
return Unauthorized("Account is not a seller.");
|
||||
}
|
||||
|
||||
if(existingSellerProfile.Suspended)
|
||||
return BadRequest("Seller is suspended.");
|
||||
|
||||
var url = await _storageService.UploadImageAsync(file, Guid.NewGuid().ToString());
|
||||
var portfolio = new SellerProfilePortfolioPiece()
|
||||
{
|
||||
SellerProfileId = existingSellerProfile.Id,
|
||||
FileReference = url,
|
||||
SellerServiceId = sellerServiceId
|
||||
};
|
||||
portfolio.SellerProfileId = existingSellerProfile.Id;
|
||||
_dbContext.SellerProfilePortfolioPieces.Add(portfolio);
|
||||
await _dbContext.SaveChangesAsync();
|
||||
var result = portfolio.ToModel();
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[Authorize("write:seller-service")]
|
||||
[Route("{sellerServiceId:int}/Portfolio/{portfolioId:int}")]
|
||||
public async Task<IActionResult> DeletePortfolio(int portfolioId)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var existingSellerProfile = await _dbContext.UserSellerProfiles.FirstOrDefaultAsync(sellerProfile=>sellerProfile.UserId==userId);
|
||||
if (existingSellerProfile == null)
|
||||
{
|
||||
var sellerProfileRequest = await _dbContext.SellerProfileRequests.FirstOrDefaultAsync(request=>request.UserId==userId && request.Accepted==false);
|
||||
if(sellerProfileRequest!=null)
|
||||
return BadRequest("Account has requested to be a seller and not been approved yet.");
|
||||
return Unauthorized("Account is not a seller.");
|
||||
}
|
||||
if(existingSellerProfile.Suspended)
|
||||
return BadRequest("Seller is suspended.");
|
||||
var portfolio = await _dbContext.SellerProfilePortfolioPieces.FirstOrDefaultAsync(x=>x.Id==portfolioId);
|
||||
if(portfolio==null)
|
||||
return NotFound("Portfolio piece not found.");
|
||||
if(portfolio.SellerProfileId!=existingSellerProfile.Id)
|
||||
return BadRequest("Portfolio piece does not belong to this seller.");
|
||||
_dbContext.SellerProfilePortfolioPieces.Remove(portfolio);
|
||||
await _dbContext.SaveChangesAsync();
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
|
45
src/comissions.app.api/Controllers/UserController.cs
Normal file
45
src/comissions.app.api/Controllers/UserController.cs
Normal file
@ -0,0 +1,45 @@
|
||||
using System.Security.Claims;
|
||||
using comissions.app.api.Extensions;
|
||||
using ArtPlatform.Database;
|
||||
using comissions.app.api.Models.User;
|
||||
using comissions.app.database;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace comissions.app.api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class UserController : Controller
|
||||
{
|
||||
private readonly ApplicationDbContext _dbContext;
|
||||
|
||||
public UserController(ApplicationDbContext dbContext)
|
||||
{
|
||||
_dbContext = dbContext;
|
||||
}
|
||||
|
||||
[Authorize("read:user")]
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetUser()
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var user = await _dbContext.Users.FirstAsync(user=>user.Id==userId);
|
||||
var result = user.ToModel();
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[Authorize("write:user")]
|
||||
[HttpPut]
|
||||
public async Task<IActionResult> UpdateUser(UserInfoUpdateModel model)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var existingUser = await _dbContext.Users.FirstAsync(user=>user.Id==userId);
|
||||
var updatedUser = model.ToEntity(existingUser);
|
||||
updatedUser = _dbContext.Users.Update(updatedUser).Entity;
|
||||
await _dbContext.SaveChangesAsync();
|
||||
var result = updatedUser.ToModel();
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
24
src/comissions.app.api/Dockerfile
Normal file
24
src/comissions.app.api/Dockerfile
Normal file
@ -0,0 +1,24 @@
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
|
||||
USER $APP_UID
|
||||
WORKDIR /app
|
||||
EXPOSE 8080
|
||||
EXPOSE 8081
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||
ARG BUILD_CONFIGURATION=Release
|
||||
WORKDIR /src
|
||||
COPY ["/src/ArtPlatform.API/ArtPlatform.API.csproj", "ArtPlatform.API/"]
|
||||
COPY ["/src/ArtPlatform.Database/ArtPlatform.Database.csproj", "ArtPlatform.Database/"]
|
||||
RUN dotnet restore "ArtPlatform.API/ArtPlatform.API.csproj"
|
||||
COPY . .
|
||||
WORKDIR "/src/ArtPlatform.API"
|
||||
RUN dotnet build "ArtPlatform.API.csproj" -c $BUILD_CONFIGURATION -o /app/build
|
||||
|
||||
FROM build AS publish
|
||||
ARG BUILD_CONFIGURATION=Release
|
||||
RUN dotnet publish "ArtPlatform.API.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
|
||||
|
||||
FROM base AS final
|
||||
WORKDIR /app
|
||||
COPY --from=publish /app/publish .
|
||||
ENTRYPOINT ["dotnet", "ArtPlatform.API.dll"]
|
11
src/comissions.app.api/Extensions/UserExtension.cs
Normal file
11
src/comissions.app.api/Extensions/UserExtension.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace comissions.app.api.Extensions;
|
||||
|
||||
public static class UserExtension
|
||||
{
|
||||
public static string GetUserId(this ClaimsPrincipal user)
|
||||
{
|
||||
return user.Claims.First(claim => claim.Type == ClaimTypes.NameIdentifier).Value;
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace comissions.app.api.Middleware.Authentication;
|
||||
|
||||
public class HasScopeHandler : AuthorizationHandler<HasScopeRequirement>
|
||||
{
|
||||
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, HasScopeRequirement requirement)
|
||||
{
|
||||
// If user does not have the scope claim, get out of here
|
||||
if (!context.User.HasClaim(c => c.Type == "scope" && c.Issuer == requirement.Issuer))
|
||||
return Task.CompletedTask;
|
||||
|
||||
// Split the scopes string into an array
|
||||
var scopes = context.User.FindFirst(c => c.Type == "scope" && c.Issuer == requirement.Issuer).Value.Split(' ');
|
||||
|
||||
// Succeed if the scope array contains the required scope
|
||||
if (scopes.Any(s => s == requirement.Scope))
|
||||
context.Succeed(requirement);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace comissions.app.api.Middleware.Authentication;
|
||||
|
||||
public class HasScopeRequirement : IAuthorizationRequirement
|
||||
{
|
||||
public string Issuer { get; }
|
||||
public string Scope { get; }
|
||||
|
||||
public HasScopeRequirement(string scope, string issuer)
|
||||
{
|
||||
Scope = scope ?? throw new ArgumentNullException(nameof(scope));
|
||||
Issuer = issuer ?? throw new ArgumentNullException(nameof(issuer));
|
||||
}
|
||||
}
|
117
src/comissions.app.api/Middleware/UserMiddleware.cs
Normal file
117
src/comissions.app.api/Middleware/UserMiddleware.cs
Normal file
@ -0,0 +1,117 @@
|
||||
using System.Security.Claims;
|
||||
using ArtPlatform.Database;
|
||||
using ArtPlatform.Database.Entities;
|
||||
using comissions.app.api.Services.Payment;
|
||||
using comissions.app.database;
|
||||
using comissions.app.database.Entities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace comissions.app.api.Middleware;
|
||||
|
||||
|
||||
public class UserMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
|
||||
public UserMiddleware(RequestDelegate next)
|
||||
{
|
||||
_next = next;
|
||||
}
|
||||
|
||||
public async Task InvokeAsync(HttpContext context, ApplicationDbContext dbContext, IPaymentService paymentService)
|
||||
{
|
||||
if (context.User.Identity.IsAuthenticated)
|
||||
{
|
||||
var userId = context.User.Claims.First(c => c.Type == ClaimTypes.NameIdentifier).Value;
|
||||
|
||||
var user = await dbContext.Users.Include(x=>x.UserSellerProfile).FirstOrDefaultAsync(x=>x.Id==userId);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
user = new User
|
||||
{
|
||||
Id = userId,
|
||||
DisplayName = context.User.Claims.FirstOrDefault(x=>x.Type==ClaimTypes.Name)?.Value ?? "Anonymous",
|
||||
Biography = string.Empty,
|
||||
Email = context.User.Claims.FirstOrDefault(x=>x.Type==ClaimTypes.Email)?.Value ?? string.Empty,
|
||||
};
|
||||
dbContext.Users.Add(user);
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
user.Email= context.User.Claims.FirstOrDefault(x=>x.Type==ClaimTypes.Email)?.Value ?? string.Empty;
|
||||
dbContext.Users.Update(user);
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
if (user.Suspended)
|
||||
{
|
||||
if (user.UnsuspendDate < DateTime.UtcNow)
|
||||
{
|
||||
user.Suspended = false;
|
||||
user.SuspendedDate = null;
|
||||
user.UnsuspendDate = null;
|
||||
user.SuspendedReason = null;
|
||||
user.SuspendAdminId = null;
|
||||
dbContext.Users.Update(user);
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
var suspendDate = user.SuspendedDate.Value.ToString("MM/dd/yyyy");
|
||||
var unsuspendDate = user.UnsuspendDate.Value.ToString("MM/dd/yyyy");
|
||||
await context.Response.WriteAsync($"Suspended on {suspendDate} until {unsuspendDate} for {user.SuspendedReason} by {user.SuspendAdminId}.");
|
||||
context.Response.StatusCode = StatusCodes.Status403Forbidden;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (user.Banned)
|
||||
{
|
||||
if (user.UnsuspendDate < DateTime.UtcNow)
|
||||
{
|
||||
user.Banned = false;
|
||||
user.BannedDate = null;
|
||||
user.BannedDate = null;
|
||||
user.BannedReason = null;
|
||||
user.BanAdminId = null;
|
||||
dbContext.Users.Update(user);
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
var suspendDate = user.BannedDate.Value.ToString("MM/dd/yyyy");
|
||||
var unsuspendDate = user.UnbanDate.Value.ToString("MM/dd/yyyy");
|
||||
await context.Response.WriteAsync($"Banned on {suspendDate} until {unsuspendDate} for {user.BannedReason} by {user.BanAdminId}.");
|
||||
context.Response.StatusCode = StatusCodes.Status403Forbidden;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (user.UserSellerProfile != null && user.UserSellerProfile.Suspended)
|
||||
{
|
||||
if (user.UserSellerProfile.UnsuspendDate < DateTime.UtcNow)
|
||||
{
|
||||
user.UserSellerProfile.Suspended = false;
|
||||
user.UserSellerProfile.SuspendedDate = null;
|
||||
user.UserSellerProfile.UnsuspendDate = null;
|
||||
user.UserSellerProfile.SuspendedReason = null;
|
||||
user.UserSellerProfile.SuspendAdminId = null;
|
||||
dbContext.Users.Update(user);
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
var suspendDate = user.UserSellerProfile.SuspendedDate.Value.ToString("MM/dd/yyyy");
|
||||
var unsuspendDate = user.UserSellerProfile.UnsuspendDate.Value.ToString("MM/dd/yyyy");
|
||||
await context.Response.WriteAsync($"Banned on {suspendDate} until {unsuspendDate} for {user.UserSellerProfile.SuspendedReason} by {user.UserSellerProfile.SuspendAdminId}.");
|
||||
context.Response.StatusCode = StatusCodes.Status403Forbidden;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await _next(context);
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
namespace comissions.app.api.Models.Discovery;
|
||||
|
||||
public class DiscoveryReviewModel
|
||||
{
|
||||
public string WriterDisplayName { get; set; }
|
||||
public string WriterId { get; set; }
|
||||
public double Rating { get; set; }
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
namespace comissions.app.api.Models.Discovery;
|
||||
|
||||
public class DiscoverySellerModel
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public List<string> SocialMediaLinks { get; set; }
|
||||
public string Biography { get; set; }
|
||||
public bool PrepaymentRequired { get; set; }
|
||||
}
|
10
src/comissions.app.api/Models/Order/MessageModel.cs
Normal file
10
src/comissions.app.api/Models/Order/MessageModel.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace comissions.app.api.Models.Order;
|
||||
|
||||
public class MessageModel
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string SenderId { get; set; }
|
||||
public string SenderDisplayName { get; set; }
|
||||
public string Message { get; set; }
|
||||
public int[] Attachments { get; set; }
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
using ArtPlatform.Database.Entities;
|
||||
using comissions.app.database.Entities;
|
||||
|
||||
namespace comissions.app.api.Models.Order;
|
||||
|
||||
public static class MessageModelExtensions
|
||||
{
|
||||
|
||||
public static MessageModel ToModel(this SellerServiceOrderMessage sellerProfile)
|
||||
{
|
||||
return new MessageModel()
|
||||
{
|
||||
Id = sellerProfile.Id,
|
||||
SenderId = sellerProfile.SenderId,
|
||||
SenderDisplayName = sellerProfile.Sender.DisplayName,
|
||||
Message = sellerProfile.Message,
|
||||
Attachments = sellerProfile.Attachments.Select(x=>x.Id).ToArray()
|
||||
};
|
||||
}
|
||||
}
|
16
src/comissions.app.api/Models/Order/OrderModel.cs
Normal file
16
src/comissions.app.api/Models/Order/OrderModel.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using comissions.app.database.Enums;
|
||||
|
||||
namespace comissions.app.api.Models.Order;
|
||||
|
||||
public class OrderModel
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string BuyerId { get; set; }
|
||||
public int SellerServiceId { get; set; }
|
||||
public int SellerId { get; set; }
|
||||
public EnumOrderStatus Status { get; set; }
|
||||
|
||||
public string StatusLabel => Status.ToString();
|
||||
public double Price { get; set; }
|
||||
public string? PaymentUrl { get; set; }
|
||||
}
|
22
src/comissions.app.api/Models/Order/OrderModelExtensions.cs
Normal file
22
src/comissions.app.api/Models/Order/OrderModelExtensions.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using ArtPlatform.Database.Entities;
|
||||
using comissions.app.database.Entities;
|
||||
|
||||
namespace comissions.app.api.Models.Order;
|
||||
|
||||
public static class OrderModelExtensions
|
||||
{
|
||||
|
||||
public static OrderModel ToModel(this SellerServiceOrder sellerProfile)
|
||||
{
|
||||
return new OrderModel()
|
||||
{
|
||||
Id = sellerProfile.Id,
|
||||
BuyerId = sellerProfile.BuyerId,
|
||||
SellerServiceId = sellerProfile.SellerServiceId,
|
||||
SellerId = sellerProfile.SellerId,
|
||||
Status = sellerProfile.Status,
|
||||
Price = sellerProfile.Price,
|
||||
PaymentUrl = sellerProfile.PaymentUrl
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
namespace ArtPlatform.Database.Entities;
|
||||
|
||||
public class SellerServiceOrderMessageModel
|
||||
{
|
||||
public string Message { get; set; }
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
namespace comissions.app.api.Models.Order;
|
||||
|
||||
public class SellerServiceOrderReviewModel
|
||||
{
|
||||
public int Rating { get; set; }
|
||||
public string? Review { get; set; }
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
namespace comissions.app.api.Models.PortfolioModel;
|
||||
|
||||
public class PortfolioModel
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public int? SellerServiceId { get; set; }
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
using ArtPlatform.Database.Entities;
|
||||
using comissions.app.database.Entities;
|
||||
|
||||
namespace comissions.app.api.Models.PortfolioModel;
|
||||
|
||||
public static class PortfolioModelExtensions
|
||||
{
|
||||
public static PortfolioModel ToModel(this SellerProfilePortfolioPiece sellerProfileRequest)
|
||||
{
|
||||
return new PortfolioModel()
|
||||
{
|
||||
Id = sellerProfileRequest.Id,
|
||||
SellerServiceId = sellerProfileRequest.SellerServiceId
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
namespace comissions.app.api.Models.SellerProfile;
|
||||
|
||||
public class SellerProfileModel
|
||||
{
|
||||
public List<string> SocialMediaLinks { get; set; }
|
||||
public string Biography { get; set; }
|
||||
public bool PrepaymentRequired { get; set; }
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
using ArtPlatform.Database.Entities;
|
||||
using comissions.app.api.Models.Discovery;
|
||||
using comissions.app.database.Entities;
|
||||
|
||||
namespace comissions.app.api.Models.SellerProfile;
|
||||
|
||||
public static class SellerProfileModelExtensions
|
||||
{
|
||||
public static SellerProfileModel ToModel(this UserSellerProfile sellerProfile)
|
||||
{
|
||||
return new SellerProfileModel()
|
||||
{
|
||||
SocialMediaLinks = sellerProfile.SocialMediaLinks,
|
||||
Biography = sellerProfile.Biography,
|
||||
PrepaymentRequired = sellerProfile.PrepaymentRequired
|
||||
};
|
||||
}
|
||||
public static DiscoverySellerModel ToDiscoveryModel(this UserSellerProfile sellerProfile)
|
||||
{
|
||||
return new DiscoverySellerModel()
|
||||
{
|
||||
Id = sellerProfile.Id,
|
||||
SocialMediaLinks = sellerProfile.SocialMediaLinks,
|
||||
Biography = sellerProfile.Biography,
|
||||
PrepaymentRequired = sellerProfile.PrepaymentRequired
|
||||
};
|
||||
}
|
||||
public static UserSellerProfile ToModel(this SellerProfileModel sellerProfile, UserSellerProfile existingSellerProfile)
|
||||
{
|
||||
existingSellerProfile.SocialMediaLinks = sellerProfile.SocialMediaLinks;
|
||||
existingSellerProfile.Biography = sellerProfile.Biography;
|
||||
existingSellerProfile.PrepaymentRequired = sellerProfile.PrepaymentRequired;
|
||||
return existingSellerProfile;
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
namespace comissions.app.api.Models.SellerProfileRequest;
|
||||
|
||||
public class SellerProfileRequestModel
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public DateTime RequestDate { get; set; }
|
||||
public string UserId { get; set; }
|
||||
public bool Accepted { get; set; }
|
||||
|
||||
public virtual database.Entities.User User { get; set; } = null!;
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
namespace comissions.app.api.Models.SellerProfileRequest;
|
||||
|
||||
public static class SellerProfileRequestModelExtensions
|
||||
{
|
||||
public static SellerProfileRequestModel ToModel(this database.Entities.SellerProfileRequest sellerProfileRequest)
|
||||
{
|
||||
return new SellerProfileRequestModel()
|
||||
{
|
||||
Id = sellerProfileRequest.Id,
|
||||
UserId = sellerProfileRequest.UserId,
|
||||
RequestDate = sellerProfileRequest.RequestDate,
|
||||
Accepted = sellerProfileRequest.Accepted
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
namespace comissions.app.api.Models.SellerService;
|
||||
|
||||
public class SellerServiceCreateModel
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Description { get; set; }
|
||||
public double Price { get; set; }
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
namespace comissions.app.api.Models.SellerService;
|
||||
|
||||
public class SellerServiceModel
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; } = null!;
|
||||
public string Description { get; set; } = null!;
|
||||
public double Price { get; set; }
|
||||
public double AverageRating { get; set; }
|
||||
public int NumberOfRatings { get; set; }
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
namespace comissions.app.api.Models.SellerService;
|
||||
|
||||
public static class SellerServiceModelExtensions
|
||||
{
|
||||
|
||||
public static SellerServiceModel ToModel(this database.Entities.SellerService sellerProfileRequest)
|
||||
{
|
||||
double avgRating = 0;
|
||||
int reviewCount = 0;
|
||||
var ratings = sellerProfileRequest.Reviews;
|
||||
if (ratings.Any())
|
||||
{
|
||||
avgRating = ratings.Average(x => x.Rating);
|
||||
reviewCount = sellerProfileRequest.Reviews.Count;
|
||||
}
|
||||
return new SellerServiceModel()
|
||||
{
|
||||
Id = sellerProfileRequest.Id,
|
||||
Name = sellerProfileRequest.Name,
|
||||
Description = sellerProfileRequest.Description,
|
||||
Price = sellerProfileRequest.Price,
|
||||
AverageRating = avgRating,
|
||||
NumberOfRatings = reviewCount
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
namespace comissions.app.api.Models.SellerService;
|
||||
|
||||
public class SellerServiceUpdateModel
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Description { get; set; }
|
||||
public double Price { get; set; }
|
||||
}
|
9
src/comissions.app.api/Models/User/UserInfoModel.cs
Normal file
9
src/comissions.app.api/Models/User/UserInfoModel.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace comissions.app.api.Models.User;
|
||||
|
||||
public class UserInfoModel
|
||||
{
|
||||
public string Id { get; set; } = string.Empty;
|
||||
public string DisplayName { get; init; } = string.Empty;
|
||||
public string Biography { get; init; } = string.Empty;
|
||||
public string Email { get; init; } = string.Empty;
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
namespace comissions.app.api.Models.User;
|
||||
|
||||
public static class UserInfoModelExtensions
|
||||
{
|
||||
public static UserInfoModel ToModel(this database.Entities.User user)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Id = user.Id,
|
||||
DisplayName = user.DisplayName,
|
||||
Biography = user.Biography,
|
||||
Email = user.Email
|
||||
};
|
||||
}
|
||||
public static database.Entities.User ToEntity(this UserInfoUpdateModel user, database.Entities.User existingUser)
|
||||
{
|
||||
existingUser.DisplayName = user.DisplayName;
|
||||
existingUser.Biography = user.Biography;
|
||||
return existingUser;
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
namespace comissions.app.api.Models.User;
|
||||
|
||||
public class UserInfoUpdateModel
|
||||
{
|
||||
public string DisplayName { get; init; } = string.Empty;
|
||||
public string Biography { get; init; } = string.Empty;
|
||||
}
|
167
src/comissions.app.api/Program.cs
Normal file
167
src/comissions.app.api/Program.cs
Normal file
@ -0,0 +1,167 @@
|
||||
using System.Reflection;
|
||||
using System.Security.Claims;
|
||||
using comissions.app.api.Middleware;
|
||||
using comissions.app.api.Middleware.Authentication;
|
||||
using comissions.app.api.Services.Payment;
|
||||
using comissions.app.api.Services.Storage;
|
||||
using ArtPlatform.Database;
|
||||
using Auth0.AspNetCore.Authentication;
|
||||
using comissions.app.database;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Microsoft.OpenApi.Models;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Add services to the container.
|
||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||
|
||||
builder.Services.AddSingleton<IStorageService,ImgCdnStorageServiceProvider>();
|
||||
builder.Services.AddSingleton<IPaymentService,StripePaymentServiceProvider>();
|
||||
|
||||
builder.Services.AddHttpContextAccessor();
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddDbContext<ApplicationDbContext>();
|
||||
builder.Services.AddSwaggerGen(options =>
|
||||
{
|
||||
options.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo
|
||||
{
|
||||
Title = "API Documentation",
|
||||
Version = "v1.0",
|
||||
Description = ""
|
||||
});
|
||||
options.ResolveConflictingActions(x => x.First());
|
||||
options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
|
||||
{
|
||||
Type = SecuritySchemeType.OAuth2,
|
||||
BearerFormat = "JWT",
|
||||
Flows = new OpenApiOAuthFlows
|
||||
{
|
||||
Implicit = new OpenApiOAuthFlow
|
||||
{
|
||||
TokenUrl = new Uri($"{builder.Configuration.GetValue<string>("Auth0:Domain")}oauth/token"),
|
||||
AuthorizationUrl = new Uri($"{builder.Configuration.GetValue<string>("Auth0:Domain")}authorize?audience={builder.Configuration.GetValue<string>("Auth0:Audience")}"),
|
||||
Scopes = new Dictionary<string, string>
|
||||
{
|
||||
{ "openid", "OpenId" },
|
||||
{ "email", "Email" },
|
||||
{ "profile", "Profile" },
|
||||
{ "read:user", "Read your profile information." },
|
||||
{ "write:user", "Update your profile information." },
|
||||
{ "read:billing-information", "Read your billing information." },
|
||||
{ "write:billing-information", "Update your billing information." },
|
||||
{ "read:seller-profile", "Read your seller profile information."},
|
||||
{ "write:seller-profile", "Update your seller profile information."},
|
||||
{ "write:seller-profile-request", "Accept seller profile requests."},
|
||||
{ "read:seller-profile-request", "Read seller profile requests."},
|
||||
{ "read:seller-service", "Read services on your seller profile."},
|
||||
{ "write:seller-service", "Update services on your seller profile."},
|
||||
{ "write:orders", "Create new orders and take action against existing ones."},
|
||||
{ "read:orders", "View your orders."},
|
||||
{ "read:seller-orders", "View orders on your seller profile."},
|
||||
{ "write:seller-orders", "Update orders on your seller profile."}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
options.AddSecurityRequirement(new OpenApiSecurityRequirement
|
||||
{
|
||||
{
|
||||
new OpenApiSecurityScheme
|
||||
{
|
||||
Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" }
|
||||
},
|
||||
new[] { "openid", "email", "profile" }
|
||||
}
|
||||
});
|
||||
|
||||
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
|
||||
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
|
||||
options.IncludeXmlComments(xmlPath);
|
||||
|
||||
});
|
||||
|
||||
builder.Services.AddControllers()
|
||||
.AddJsonOptions(options=>
|
||||
options.JsonSerializerOptions.ReferenceHandler = System.Text.Json.Serialization.ReferenceHandler.IgnoreCycles
|
||||
);
|
||||
|
||||
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
|
||||
{
|
||||
options.Authority = $"{builder.Configuration.GetValue<string>("Auth0:Domain")}";
|
||||
options.Audience = $"{builder.Configuration.GetValue<string>("Auth0:Audience")}";
|
||||
options.TokenValidationParameters = new TokenValidationParameters
|
||||
{
|
||||
NameClaimType = ClaimTypes.NameIdentifier,
|
||||
RoleClaimType = ClaimTypes.Role
|
||||
};
|
||||
});
|
||||
|
||||
builder.Services.AddAuthorization(options =>
|
||||
{
|
||||
options.AddPolicy("admin", policy => policy.RequireClaim(ClaimTypes.Role, "Admin"));
|
||||
|
||||
options.AddPolicy("read:user", policy => policy.Requirements.Add(new
|
||||
HasScopeRequirement("read:user", builder.Configuration.GetValue<string>("Auth0:Domain"))));
|
||||
options.AddPolicy("write:user", policy => policy.Requirements.Add(new
|
||||
HasScopeRequirement("write:user", builder.Configuration.GetValue<string>("Auth0:Domain"))));
|
||||
|
||||
options.AddPolicy("read:billing-information", policy => policy.Requirements.Add(new
|
||||
HasScopeRequirement("read:billing-information", builder.Configuration.GetValue<string>("Auth0:Domain"))));
|
||||
options.AddPolicy("write:billing-information", policy => policy.Requirements.Add(new
|
||||
HasScopeRequirement("write:billing-information", builder.Configuration.GetValue<string>("Auth0:Domain"))));
|
||||
|
||||
options.AddPolicy("read:seller-profile", policy => policy.Requirements.Add(new
|
||||
HasScopeRequirement("read:seller-profile", builder.Configuration.GetValue<string>("Auth0:Domain"))));
|
||||
options.AddPolicy("write:seller-profile", policy => policy.Requirements.Add(new
|
||||
HasScopeRequirement("write:seller-profile", builder.Configuration.GetValue<string>("Auth0:Domain"))));
|
||||
|
||||
options.AddPolicy("read:seller-profile-request", policy => policy.Requirements.Add(new
|
||||
HasScopeRequirement("read:seller-profile-request", builder.Configuration.GetValue<string>("Auth0:Domain"))));
|
||||
options.AddPolicy("write:seller-profile-request", policy => policy.Requirements.Add(new
|
||||
HasScopeRequirement("write:seller-profile-request", builder.Configuration.GetValue<string>("Auth0:Domain"))));
|
||||
|
||||
options.AddPolicy("read:seller-service", policy => policy.Requirements.Add(new
|
||||
HasScopeRequirement("read:seller-service", builder.Configuration.GetValue<string>("Auth0:Domain"))));
|
||||
options.AddPolicy("write:seller-service", policy => policy.Requirements.Add(new
|
||||
HasScopeRequirement("write:seller-service", builder.Configuration.GetValue<string>("Auth0:Domain"))));
|
||||
|
||||
options.AddPolicy("write:orders", policy => policy.Requirements.Add(new
|
||||
HasScopeRequirement("write:orders", builder.Configuration.GetValue<string>("Auth0:Domain"))));
|
||||
options.AddPolicy("read:orders", policy => policy.Requirements.Add(new
|
||||
HasScopeRequirement("read:orders", builder.Configuration.GetValue<string>("Auth0:Domain"))));
|
||||
|
||||
options.AddPolicy("read:seller-orders", policy => policy.Requirements.Add(new
|
||||
HasScopeRequirement("read:seller-orders", builder.Configuration.GetValue<string>("Auth0:Domain"))));
|
||||
options.AddPolicy("write:seller-orders", policy => policy.Requirements.Add(new
|
||||
HasScopeRequirement("write:seller-orders", builder.Configuration.GetValue<string>("Auth0:Domain"))));
|
||||
});
|
||||
|
||||
builder.Services.AddSingleton<IAuthorizationHandler, HasScopeHandler>();
|
||||
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI(settings =>
|
||||
{
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
settings.OAuthClientId(builder.Configuration.GetValue<string>("Auth0:ClientId"));
|
||||
settings.OAuthClientSecret(builder.Configuration.GetValue<string>("Auth0:ClientSecret"));
|
||||
settings.OAuthUsePkce();
|
||||
}
|
||||
});
|
||||
var defaultFilesOptions = new DefaultFilesOptions();
|
||||
defaultFilesOptions.DefaultFileNames.Clear();
|
||||
defaultFilesOptions.DefaultFileNames.Add("index.html"); // replace 'yourf
|
||||
app.UseStaticFiles();
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
app.UseAuthentication();
|
||||
app.UseMiddleware<UserMiddleware>();
|
||||
app.UseAuthorization();
|
||||
app.MapControllers();
|
||||
app.Run();
|
41
src/comissions.app.api/Properties/launchSettings.json
Normal file
41
src/comissions.app.api/Properties/launchSettings.json
Normal file
@ -0,0 +1,41 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:35549",
|
||||
"sslPort": 44383
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "",
|
||||
"applicationUrl": "http://localhost:5290",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"applicationUrl": "https://localhost:7148;http://localhost:5290",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
12
src/comissions.app.api/Services/Payment/IPaymentService.cs
Normal file
12
src/comissions.app.api/Services/Payment/IPaymentService.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using ArtPlatform.Database.Entities;
|
||||
|
||||
namespace comissions.app.api.Services.Payment;
|
||||
|
||||
public interface IPaymentService
|
||||
{
|
||||
public string CreateCustomer();
|
||||
string CreateSellerAccount();
|
||||
string CreateSellerAccountOnboardingUrl(string accountId);
|
||||
bool SellerAccountIsOnboarded(string accountId);
|
||||
string ChargeForService(int orderSellerServiceId, string? sellerStripeAccountId, double orderPrice);
|
||||
}
|
@ -0,0 +1,130 @@
|
||||
using ArtPlatform.Database.Entities;
|
||||
using Stripe;
|
||||
|
||||
namespace comissions.app.api.Services.Payment;
|
||||
|
||||
public class StripePaymentServiceProvider:IPaymentService
|
||||
{
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly string _apiKey;
|
||||
|
||||
|
||||
public StripePaymentServiceProvider(IConfiguration configuration)
|
||||
{
|
||||
_configuration = configuration;
|
||||
_apiKey = _configuration.GetValue<string>("Stripe:ApiKey");
|
||||
StripeConfiguration.ApiKey = _apiKey;
|
||||
}
|
||||
|
||||
public string CreateCustomer()
|
||||
{
|
||||
var options = new CustomerCreateOptions
|
||||
{
|
||||
Name = "Jenny Rosen",
|
||||
Email = "jennyrosen@example.com",
|
||||
};
|
||||
var service = new CustomerService();
|
||||
var customer = service.Create(options);
|
||||
return customer.Id;
|
||||
}
|
||||
|
||||
// public string ChargeCustomer(string customerId, int amount)
|
||||
// {
|
||||
// var options = new PaymentIntentCreateOptions
|
||||
// {
|
||||
// Amount = amount,
|
||||
// Currency = "usd",
|
||||
// AutomaticPaymentMethods = new PaymentIntentAutomaticPaymentMethodsOptions
|
||||
// {
|
||||
// Enabled = true,
|
||||
// },
|
||||
// };
|
||||
// var requestOptions = new RequestOptions
|
||||
// {
|
||||
// StripeAccount = "{{CONNECTED_ACCOUNT_ID}}",
|
||||
// };
|
||||
// var service = new PaymentIntentService();
|
||||
// var intent = service.Create(options, requestOptions);
|
||||
// throw new NotImplementedException();
|
||||
// }
|
||||
public string CreateSellerAccount()
|
||||
{
|
||||
var accountCreateOptions = new AccountCreateOptions { Type = "express",
|
||||
Capabilities
|
||||
= new AccountCapabilitiesOptions
|
||||
{
|
||||
CardPayments
|
||||
= new AccountCapabilitiesCardPaymentsOptions { Requested
|
||||
= true },
|
||||
Transfers
|
||||
= new AccountCapabilitiesTransfersOptions { Requested
|
||||
= true },
|
||||
} };
|
||||
var accountService = new AccountService();
|
||||
var account = accountService.Create(accountCreateOptions);
|
||||
return account.Id;
|
||||
}
|
||||
|
||||
public string CreateSellerAccountOnboardingUrl(string accountId)
|
||||
{
|
||||
var options = new AccountLinkCreateOptions
|
||||
{
|
||||
Account = accountId,
|
||||
RefreshUrl = "https://example.com/reauth",
|
||||
ReturnUrl = "https://example.com/return",
|
||||
Type = "account_onboarding",
|
||||
};
|
||||
var service = new AccountLinkService();
|
||||
var url = service.Create(options);
|
||||
return url.Url;
|
||||
}
|
||||
|
||||
public bool SellerAccountIsOnboarded(string accountId)
|
||||
{
|
||||
var service = new AccountService();
|
||||
var account = service.Get(accountId);
|
||||
return account.Requirements.CurrentlyDue.Count == 0 && account.ChargesEnabled==true && account.DetailsSubmitted==true;
|
||||
}
|
||||
|
||||
public string ChargeForService(int orderSellerServiceOrderId, string? sellerStripeAccountId,
|
||||
double orderPrice)
|
||||
{
|
||||
var feeAmount = (long)Math.Round((orderPrice*0.05) * 100);
|
||||
var options = new Stripe.Checkout.SessionCreateOptions
|
||||
{
|
||||
LineItems = new List<Stripe.Checkout.SessionLineItemOptions> {
|
||||
new Stripe.Checkout.SessionLineItemOptions
|
||||
{
|
||||
PriceData = new Stripe.Checkout.SessionLineItemPriceDataOptions
|
||||
{
|
||||
UnitAmount = (long)Math.Round(orderPrice * 100),
|
||||
Currency = "usd",
|
||||
ProductData = new Stripe.Checkout.SessionLineItemPriceDataProductDataOptions
|
||||
{
|
||||
Name = "Comission Service",
|
||||
},
|
||||
},
|
||||
Quantity = 1,
|
||||
},
|
||||
},
|
||||
PaymentIntentData = new Stripe.Checkout.SessionPaymentIntentDataOptions
|
||||
{
|
||||
ApplicationFeeAmount = feeAmount,
|
||||
},
|
||||
Mode = "payment",
|
||||
SuccessUrl = "https://example.com/success",
|
||||
CancelUrl = "https://example.com/failure",
|
||||
Metadata = new Dictionary<string, string>()
|
||||
{
|
||||
["orderId"] = orderSellerServiceOrderId.ToString()
|
||||
}
|
||||
};
|
||||
var requestOptions = new RequestOptions
|
||||
{
|
||||
StripeAccount = sellerStripeAccountId
|
||||
};
|
||||
var service = new Stripe.Checkout.SessionService();
|
||||
var session = service.Create(options, requestOptions);
|
||||
return session.Url;
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
namespace comissions.app.api.Services.Storage;
|
||||
|
||||
public interface IStorageService
|
||||
{
|
||||
public Task<string> UploadImageAsync(IFormFile file, string fileName);
|
||||
public Task<Stream> DownloadImageAsync(string fileRefrence);
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
using System.Net.Http;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace comissions.app.api.Services.Storage
|
||||
{
|
||||
public class ImgCdnStorageServiceProvider : IStorageService
|
||||
{
|
||||
private readonly HttpClient _client;
|
||||
private const string ApiKey = "5386e05a3562c7a8f984e73401540836";
|
||||
|
||||
public ImgCdnStorageServiceProvider()
|
||||
{
|
||||
_client = new HttpClient { BaseAddress = new Uri("https://imgcdn.dev/") };
|
||||
}
|
||||
|
||||
public async Task<string> UploadImageAsync(IFormFile file, string fileName)
|
||||
{
|
||||
using var content = new MultipartFormDataContent();
|
||||
content.Add(new StringContent(ApiKey), "key");
|
||||
|
||||
using var fileStream = file.OpenReadStream();
|
||||
content.Add(new StreamContent(fileStream), "source", fileName);
|
||||
|
||||
var response = await _client.PostAsync("api/1/upload", content);
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
throw new Exception("Failed to upload image.");
|
||||
}
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var jsonResponse = JsonDocument.Parse(responseContent);
|
||||
var imageUrl = jsonResponse.RootElement.GetProperty("image").GetProperty("url").GetString();
|
||||
|
||||
return imageUrl;
|
||||
}
|
||||
|
||||
public async Task<Stream> DownloadImageAsync(string fileReference)
|
||||
{
|
||||
var response = await _client.GetAsync(fileReference);
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
throw new Exception("Failed to download image.");
|
||||
}
|
||||
|
||||
var stream = await response.Content.ReadAsStreamAsync();
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
}
|
8
src/comissions.app.api/appsettings.Development.json
Normal file
8
src/comissions.app.api/appsettings.Development.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
19
src/comissions.app.api/appsettings.json
Normal file
19
src/comissions.app.api/appsettings.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"Stripe": {
|
||||
"WebHookSecret": "whsec_Jdj6IL9NwFO3MtPpry3vJhE72kZjeCtI",
|
||||
"ApiKey": "sk_test_51OdJ1SLooS0IZqYkx2IdNoLcscm6BisgaUyYVIc5jM1RMmarww2e9hLLQS3Atn6TQi00p9YQkCLGQPhAI2gf9ZSY00HmbQYCvP"
|
||||
},
|
||||
"Auth0": {
|
||||
"Domain": "https://dev-12mb5yq82dow1twh.us.auth0.com/",
|
||||
"Audience": "https://api.artplatform.com",
|
||||
"ClientId": "19GWUL7fWFQWEpdFFtlgv2x3kqfSa0ES",
|
||||
"ClientSecret": "VX5LKeGHeaqKsgNz8Kn1gQ7MSHmwrXJdC2DMjVY82_YHjiRqdPrVNpFFkXBZy8yh"
|
||||
},
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Trace",
|
||||
"Microsoft.AspNetCore": "Trace"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
BIN
src/comissions.app.api/bin/Debug/net8.0/ArtPlatform.API
Executable file
BIN
src/comissions.app.api/bin/Debug/net8.0/ArtPlatform.API
Executable file
Binary file not shown.
1988
src/comissions.app.api/bin/Debug/net8.0/ArtPlatform.API.deps.json
Normal file
1988
src/comissions.app.api/bin/Debug/net8.0/ArtPlatform.API.deps.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,22 @@
|
||||
{
|
||||
"runtimeOptions": {
|
||||
"tfm": "net8.0",
|
||||
"frameworks": [
|
||||
{
|
||||
"name": "Microsoft.NETCore.App",
|
||||
"version": "8.0.0"
|
||||
},
|
||||
{
|
||||
"name": "Microsoft.AspNetCore.App",
|
||||
"version": "8.0.0"
|
||||
}
|
||||
],
|
||||
"configProperties": {
|
||||
"System.GC.Server": true,
|
||||
"System.Globalization.Invariant": true,
|
||||
"System.Globalization.PredefinedCulturesOnly": true,
|
||||
"System.Reflection.NullabilityInfoContext.IsSupported": true,
|
||||
"System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false
|
||||
}
|
||||
}
|
||||
}
|
29
src/comissions.app.api/bin/Debug/net8.0/ArtPlatform.API.xml
Normal file
29
src/comissions.app.api/bin/Debug/net8.0/ArtPlatform.API.xml
Normal file
@ -0,0 +1,29 @@
|
||||
<?xml version="1.0"?>
|
||||
<doc>
|
||||
<assembly>
|
||||
<name>ArtPlatform.API</name>
|
||||
</assembly>
|
||||
<members>
|
||||
<member name="M:ArtPlatform.API.Controllers.AdminSellerRequestsController.GetSellerRequests(System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Gets a list of all of the requests from users to become a seller.
|
||||
</summary>
|
||||
<param name="offset"> The offset to start at.</param>
|
||||
<param name="pageSize"> The amount of records to return.</param>
|
||||
<returns>A list of seller profile requests</returns>
|
||||
</member>
|
||||
<member name="M:ArtPlatform.API.Controllers.AdminSellerRequestsController.GetSellerRequestsCount">
|
||||
<summary>
|
||||
Gets the amount of requests there are from users to become a seller.
|
||||
</summary>
|
||||
<returns>The number of requests.</returns>
|
||||
</member>
|
||||
<member name="M:ArtPlatform.API.Controllers.AdminSellerRequestsController.AcceptSellerRequest(System.String)">
|
||||
<summary>
|
||||
Accepts a request to become a seller from a user.
|
||||
</summary>
|
||||
<param name="userId">The ID of the user to accept the request for.</param>
|
||||
<returns>The new seller profile.</returns>
|
||||
</member>
|
||||
</members>
|
||||
</doc>
|
BIN
src/comissions.app.api/bin/Debug/net8.0/ArtPlatform.Database.dll
Normal file
BIN
src/comissions.app.api/bin/Debug/net8.0/ArtPlatform.Database.dll
Normal file
Binary file not shown.
BIN
src/comissions.app.api/bin/Debug/net8.0/ArtPlatform.Database.pdb
Normal file
BIN
src/comissions.app.api/bin/Debug/net8.0/ArtPlatform.Database.pdb
Normal file
Binary file not shown.
BIN
src/comissions.app.api/bin/Debug/net8.0/Auth0.AspNetCore.Authentication.dll
Executable file
BIN
src/comissions.app.api/bin/Debug/net8.0/Auth0.AspNetCore.Authentication.dll
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
src/comissions.app.api/bin/Debug/net8.0/Microsoft.AspNetCore.OpenApi.dll
Executable file
BIN
src/comissions.app.api/bin/Debug/net8.0/Microsoft.AspNetCore.OpenApi.dll
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
src/comissions.app.api/bin/Debug/net8.0/Microsoft.EntityFrameworkCore.dll
Executable file
BIN
src/comissions.app.api/bin/Debug/net8.0/Microsoft.EntityFrameworkCore.dll
Executable file
Binary file not shown.
Binary file not shown.
BIN
src/comissions.app.api/bin/Debug/net8.0/Microsoft.IdentityModel.Abstractions.dll
Executable file
BIN
src/comissions.app.api/bin/Debug/net8.0/Microsoft.IdentityModel.Abstractions.dll
Executable file
Binary file not shown.
Binary file not shown.
BIN
src/comissions.app.api/bin/Debug/net8.0/Microsoft.IdentityModel.Logging.dll
Executable file
BIN
src/comissions.app.api/bin/Debug/net8.0/Microsoft.IdentityModel.Logging.dll
Executable file
Binary file not shown.
Binary file not shown.
BIN
src/comissions.app.api/bin/Debug/net8.0/Microsoft.IdentityModel.Protocols.dll
Executable file
BIN
src/comissions.app.api/bin/Debug/net8.0/Microsoft.IdentityModel.Protocols.dll
Executable file
Binary file not shown.
BIN
src/comissions.app.api/bin/Debug/net8.0/Microsoft.IdentityModel.Tokens.dll
Executable file
BIN
src/comissions.app.api/bin/Debug/net8.0/Microsoft.IdentityModel.Tokens.dll
Executable file
Binary file not shown.
BIN
src/comissions.app.api/bin/Debug/net8.0/Microsoft.OpenApi.dll
Executable file
BIN
src/comissions.app.api/bin/Debug/net8.0/Microsoft.OpenApi.dll
Executable file
Binary file not shown.
BIN
src/comissions.app.api/bin/Debug/net8.0/Microsoft.Win32.SystemEvents.dll
Executable file
BIN
src/comissions.app.api/bin/Debug/net8.0/Microsoft.Win32.SystemEvents.dll
Executable file
Binary file not shown.
BIN
src/comissions.app.api/bin/Debug/net8.0/Newtonsoft.Json.dll
Executable file
BIN
src/comissions.app.api/bin/Debug/net8.0/Newtonsoft.Json.dll
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
src/comissions.app.api/bin/Debug/net8.0/Npgsql.dll
Executable file
BIN
src/comissions.app.api/bin/Debug/net8.0/Npgsql.dll
Executable file
Binary file not shown.
BIN
src/comissions.app.api/bin/Debug/net8.0/Stripe.net.dll
Executable file
BIN
src/comissions.app.api/bin/Debug/net8.0/Stripe.net.dll
Executable file
Binary file not shown.
BIN
src/comissions.app.api/bin/Debug/net8.0/Swashbuckle.AspNetCore.Swagger.dll
Executable file
BIN
src/comissions.app.api/bin/Debug/net8.0/Swashbuckle.AspNetCore.Swagger.dll
Executable file
Binary file not shown.
BIN
src/comissions.app.api/bin/Debug/net8.0/Swashbuckle.AspNetCore.SwaggerGen.dll
Executable file
BIN
src/comissions.app.api/bin/Debug/net8.0/Swashbuckle.AspNetCore.SwaggerGen.dll
Executable file
Binary file not shown.
BIN
src/comissions.app.api/bin/Debug/net8.0/Swashbuckle.AspNetCore.SwaggerUI.dll
Executable file
BIN
src/comissions.app.api/bin/Debug/net8.0/Swashbuckle.AspNetCore.SwaggerUI.dll
Executable file
Binary file not shown.
Binary file not shown.
BIN
src/comissions.app.api/bin/Debug/net8.0/System.Drawing.Common.dll
Executable file
BIN
src/comissions.app.api/bin/Debug/net8.0/System.Drawing.Common.dll
Executable file
Binary file not shown.
BIN
src/comissions.app.api/bin/Debug/net8.0/System.IdentityModel.Tokens.Jwt.dll
Executable file
BIN
src/comissions.app.api/bin/Debug/net8.0/System.IdentityModel.Tokens.Jwt.dll
Executable file
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user