Finally deployed
This commit is contained in:
parent
4596d7aa99
commit
d60be0ccaa
@ -1,38 +1,40 @@
|
|||||||
# This helm values file defines app-based settings
|
# This helm values file defines app-based settings
|
||||||
# Charts use those values, so this file **MUST** be included in all chart releases
|
# Charts use those values, so this file **MUST** be included in all chart releases
|
||||||
|
|
||||||
app: # app global settings
|
app: # app global settings
|
||||||
name: "my-eshop" # Override for custom app name
|
name: "my-eshop" # Override for custom app name
|
||||||
ingress: # ingress related settings
|
ingress: # ingress related settings
|
||||||
entries:
|
entries:
|
||||||
basket: basket-api # ingress entry for basket api
|
basket: basket-api # ingress entry for basket api
|
||||||
catalog: catalog-api # ingress entry for catalog api
|
catalog: catalog-api # ingress entry for catalog api
|
||||||
ordering: ordering-api # ingress entry for ordering api
|
coupon: coupon-api # ingress entry for coupon api
|
||||||
identity: identity # ingress entry for identity api
|
ordering: ordering-api # ingress entry for ordering api
|
||||||
mvc: webmvc # ingress entry for web mvc
|
identity: identity # ingress entry for identity api
|
||||||
spa: "" # ingress entry for web spa
|
mvc: webmvc # ingress entry for web mvc
|
||||||
status: webstatus # ingress entry for web status
|
spa: "" # ingress entry for web spa
|
||||||
webshoppingapigw: webshoppingapigw # ingress entry for web shopping Agw
|
status: webstatus # ingress entry for web status
|
||||||
mobileshoppingapigw: mobileshoppingapigw # ingress entry for mobile shopping Agw
|
webshoppingapigw: webshoppingapigw # ingress entry for web shopping Agw
|
||||||
webshoppingagg: webshoppingagg # ingress entry for web shopping aggregator
|
mobileshoppingapigw: mobileshoppingapigw # ingress entry for mobile shopping Agw
|
||||||
mobileshoppingagg: mobileshoppingagg # ingress entry for mobile shopping aggregator
|
webshoppingagg: webshoppingagg # ingress entry for web shopping aggregator
|
||||||
payment: payment-api # ingress entry for payment api
|
mobileshoppingagg: mobileshoppingagg # ingress entry for mobile shopping aggregator
|
||||||
webhooks: webhooks-api # ingress entry for webhooks api
|
payment: payment-api # ingress entry for payment api
|
||||||
webhooksweb: webhooks-web # ingress entry for webhooks web demo client
|
webhooks: webhooks-api # ingress entry for webhooks api
|
||||||
|
webhooksweb: webhooks-web # ingress entry for webhooks web demo client
|
||||||
svc:
|
svc:
|
||||||
basket: basket-api # service name for basket api
|
basket: basket-api # service name for basket api
|
||||||
catalog: catalog-api # service name for catalog api
|
catalog: catalog-api # service name for catalog api
|
||||||
ordering: ordering-api # service name for ordering api
|
coupon: coupon-api # service name for coupon api
|
||||||
orderingbackgroundtasks: ordering-backgroundtasks # service name for orderingbackgroundtasks
|
ordering: ordering-api # service name for ordering api
|
||||||
orderingsignalrhub: ordering-signalrhub # service name for orderingsignalrhub
|
orderingbackgroundtasks: ordering-backgroundtasks # service name for orderingbackgroundtasks
|
||||||
identity: identity-api # service name for identity api
|
orderingsignalrhub: ordering-signalrhub # service name for orderingsignalrhub
|
||||||
mvc: webmvc # service name for web mvc
|
identity: identity-api # service name for identity api
|
||||||
spa: webspa # service name for web spa
|
mvc: webmvc # service name for web mvc
|
||||||
status: webstatus # service name for web status
|
spa: webspa # service name for web spa
|
||||||
webshoppingapigw: webshoppingapigw # service name for web shopping Agw
|
status: webstatus # service name for web status
|
||||||
mobileshoppingapigw: mobileshoppingapigw # service name for mobile shopping Agw
|
webshoppingapigw: webshoppingapigw # service name for web shopping Agw
|
||||||
webshoppingagg: webshoppingagg # service name for web shopping aggregator
|
mobileshoppingapigw: mobileshoppingapigw # service name for mobile shopping Agw
|
||||||
mobileshoppingagg: mobileshoppingagg # service name for mobile shopping aggregator
|
webshoppingagg: webshoppingagg # service name for web shopping aggregator
|
||||||
payment: payment-api # service name for payment api
|
mobileshoppingagg: mobileshoppingagg # service name for mobile shopping aggregator
|
||||||
webhooks: webhooks-api # service name for webhooks api
|
payment: payment-api # service name for payment api
|
||||||
webhooksweb: webhooks-client # service name for webhooks web
|
webhooks: webhooks-api # service name for webhooks api
|
||||||
|
webhooksweb: webhooks-client # service name for webhooks web
|
||||||
|
21
deploy/k8s/helm/coupon-api/.helmignore
Normal file
21
deploy/k8s/helm/coupon-api/.helmignore
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Patterns to ignore when building packages.
|
||||||
|
# This supports shell glob matching, relative path matching, and
|
||||||
|
# negation (prefixed with !). Only one pattern per line.
|
||||||
|
.DS_Store
|
||||||
|
# Common VCS dirs
|
||||||
|
.git/
|
||||||
|
.gitignore
|
||||||
|
.bzr/
|
||||||
|
.bzrignore
|
||||||
|
.hg/
|
||||||
|
.hgignore
|
||||||
|
.svn/
|
||||||
|
# Common backup files
|
||||||
|
*.swp
|
||||||
|
*.bak
|
||||||
|
*.tmp
|
||||||
|
*~
|
||||||
|
# Various IDEs
|
||||||
|
.project
|
||||||
|
.idea/
|
||||||
|
*.tmproj
|
5
deploy/k8s/helm/coupon-api/Chart.yaml
Normal file
5
deploy/k8s/helm/coupon-api/Chart.yaml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
appVersion: "1.0"
|
||||||
|
description: A Helm chart for Kubernetes
|
||||||
|
name: coupon-api
|
||||||
|
version: 0.1.0
|
9
deploy/k8s/helm/coupon-api/templates/NOTES.txt
Normal file
9
deploy/k8s/helm/coupon-api/templates/NOTES.txt
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
eShop Coupon API installed.
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
This API is not directly exposed outside cluster. If need to access it use:
|
||||||
|
|
||||||
|
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "coupon-api.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
|
||||||
|
echo "Visit http://127.0.0.1:8080 to use your application"
|
||||||
|
kubectl port-forward $POD_NAME 8080:80
|
||||||
|
|
32
deploy/k8s/helm/coupon-api/templates/_helpers.tpl
Normal file
32
deploy/k8s/helm/coupon-api/templates/_helpers.tpl
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
{{/* vim: set filetype=mustache: */}}
|
||||||
|
{{/*
|
||||||
|
Expand the name of the chart.
|
||||||
|
*/}}
|
||||||
|
{{- define "coupon-api.name" -}}
|
||||||
|
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create a default fully qualified app name.
|
||||||
|
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||||
|
If release name contains chart name it will be used as a full name.
|
||||||
|
*/}}
|
||||||
|
{{- define "coupon-api.fullname" -}}
|
||||||
|
{{- if .Values.fullnameOverride -}}
|
||||||
|
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- $name := default .Chart.Name .Values.nameOverride -}}
|
||||||
|
{{- if contains $name .Release.Name -}}
|
||||||
|
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create chart name and version as used by the chart label.
|
||||||
|
*/}}
|
||||||
|
{{- define "coupon-api.chart" -}}
|
||||||
|
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- end -}}
|
60
deploy/k8s/helm/coupon-api/templates/_names.tpl
Normal file
60
deploy/k8s/helm/coupon-api/templates/_names.tpl
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
{{- define "suffix-name" -}}
|
||||||
|
{{- if .Values.app.name -}}
|
||||||
|
{{- .Values.app.name -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- .Release.Name -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{- define "sql-name" -}}
|
||||||
|
{{- if .Values.inf.sql.host -}}
|
||||||
|
{{- .Values.inf.sql.host -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- printf "%s" "sql-data" -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{- define "mongo-name" -}}
|
||||||
|
{{- if .Values.inf.mongo.host -}}
|
||||||
|
{{- .Values.inf.mongo.host -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- printf "%s" "nosql-data" -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{- define "url-of" -}}
|
||||||
|
{{- $name := first .}}
|
||||||
|
{{- $ctx := last .}}
|
||||||
|
{{- if eq $name "" -}}
|
||||||
|
{{- $ctx.Values.inf.k8s.dns -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- printf "%s/%s" $ctx.Values.inf.k8s.dns $name -}} {{/*Value is just <dns>/<name> */}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{{- define "pathBase" -}}
|
||||||
|
{{- if .Values.inf.k8s.suffix -}}
|
||||||
|
{{- $suffix := include "suffix-name" . -}}
|
||||||
|
{{- printf "%s-%s" .Values.pathBase $suffix -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- .Values.pathBase -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{- define "fqdn-image" -}}
|
||||||
|
{{- if .Values.inf.registry -}}
|
||||||
|
{{- printf "%s/%s" .Values.inf.registry.server .Values.image.repository -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- .Values.image.repository -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{- define "protocol" -}}
|
||||||
|
{{- if .Values.inf.tls.enabled -}}
|
||||||
|
{{- printf "%s" "https" -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- printf "%s" "http" -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
21
deploy/k8s/helm/coupon-api/templates/configmap.yaml
Normal file
21
deploy/k8s/helm/coupon-api/templates/configmap.yaml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{{- $name := include "coupon-api.fullname" . -}}
|
||||||
|
{{- $mongo := include "mongo-name" . -}}
|
||||||
|
{{- $webshoppingapigw := include "url-of" (list .Values.app.ingress.entries.webshoppingapigw .) -}}
|
||||||
|
{{- $protocol := include "protocol" . -}}
|
||||||
|
|
||||||
|
kind: ConfigMap
|
||||||
|
apiVersion: v1
|
||||||
|
metadata:
|
||||||
|
name: "cfg-{{ $name }}"
|
||||||
|
labels:
|
||||||
|
app: {{ template "coupon-api.name" . }}
|
||||||
|
chart: {{ template "coupon-api.chart" .}}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
heritage: {{ .Release.Service }}
|
||||||
|
data:
|
||||||
|
coupon__MongoDatabase: "CouponDb"
|
||||||
|
coupon__ConnectionString: mongodb://nosql-data
|
||||||
|
urls__IdentityUrl: http://{{ .Values.app.svc.identity }}
|
||||||
|
all__EventBusConnection: {{ .Values.inf.eventbus.constr }}
|
||||||
|
all__InstrumentationKey: "{{ .Values.inf.appinsights.key }}"
|
||||||
|
all__UseAzureServiceBus: "{{ .Values.inf.eventbus.useAzure }}"
|
99
deploy/k8s/helm/coupon-api/templates/deployment.yaml
Normal file
99
deploy/k8s/helm/coupon-api/templates/deployment.yaml
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
{{- $name := include "coupon-api.fullname" . -}}
|
||||||
|
{{- $cfgname := printf "%s-%s" "cfg" $name -}}
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ template "coupon-api.fullname" . }}
|
||||||
|
labels:
|
||||||
|
ufo: {{ $cfgname}}
|
||||||
|
app: {{ template "coupon-api.name" . }}
|
||||||
|
chart: {{ template "coupon-api.chart" . }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
heritage: {{ .Release.Service }}
|
||||||
|
spec:
|
||||||
|
replicas: {{ .Values.replicaCount }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: {{ template "coupon-api.name" . }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: {{ template "coupon-api.name" . }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
{{ if .Values.inf.mesh.enabled -}}
|
||||||
|
annotations:
|
||||||
|
linkerd.io/inject: enabled
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
{{ if .Values.inf.registry -}}
|
||||||
|
imagePullSecrets:
|
||||||
|
- name: {{ .Values.inf.registry.secretName }}
|
||||||
|
{{- end }}
|
||||||
|
containers:
|
||||||
|
- name: {{ .Chart.Name }}
|
||||||
|
{{ if .Values.probes -}}
|
||||||
|
{{- if .Values.probes.liveness -}}
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
port: {{ .Values.probes.liveness.port }}
|
||||||
|
path: {{ .Values.probes.liveness.path }}
|
||||||
|
initialDelaySeconds: {{ .Values.probes.liveness.initialDelaySeconds }}
|
||||||
|
periodSeconds: {{ .Values.probes.liveness.periodSeconds }}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- if .Values.probes -}}
|
||||||
|
{{- if .Values.probes.readiness }}
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
port: {{ .Values.probes.readiness.port }}
|
||||||
|
path: {{ .Values.probes.readiness.path }}
|
||||||
|
initialDelaySeconds: {{ .Values.probes.readiness.initialDelaySeconds }}
|
||||||
|
periodSeconds: {{ .Values.probes.readiness.periodSeconds }}
|
||||||
|
timeoutSeconds: {{ .Values.probes.readiness.timeoutSeconds }}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end }}
|
||||||
|
image: "{{ template "fqdn-image" . }}:{{ .Values.image.tag }}"
|
||||||
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
|
env:
|
||||||
|
- name: PATH_BASE
|
||||||
|
value: {{ include "pathBase" . }}
|
||||||
|
- name: k8sname
|
||||||
|
value: {{ .Values.clusterName }}
|
||||||
|
{{- if .Values.env.values -}}
|
||||||
|
{{- range .Values.env.values }}
|
||||||
|
- name: {{ .name }}
|
||||||
|
value: {{ .value | quote }}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- if .Values.env.configmap -}}
|
||||||
|
{{- range .Values.env.configmap }}
|
||||||
|
- name: {{ .name }}
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ $cfgname }}
|
||||||
|
key: {{ .key }}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: 80
|
||||||
|
protocol: TCP
|
||||||
|
- name: grpc
|
||||||
|
containerPort: 81
|
||||||
|
protocol: TCP
|
||||||
|
resources:
|
||||||
|
{{ toYaml .Values.resources | indent 12 }}
|
||||||
|
{{- with .Values.nodeSelector }}
|
||||||
|
nodeSelector:
|
||||||
|
{{ toYaml . | indent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.affinity }}
|
||||||
|
affinity:
|
||||||
|
{{ toYaml . | indent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.tolerations }}
|
||||||
|
tolerations:
|
||||||
|
{{ toYaml . | indent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
|
23
deploy/k8s/helm/coupon-api/templates/service.yaml
Normal file
23
deploy/k8s/helm/coupon-api/templates/service.yaml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ .Values.app.svc.coupon }}
|
||||||
|
labels:
|
||||||
|
app: {{ template "coupon-api.name" . }}
|
||||||
|
chart: {{ template "coupon-api.chart" . }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
heritage: {{ .Release.Service }}
|
||||||
|
spec:
|
||||||
|
type: {{ .Values.service.type }}
|
||||||
|
ports:
|
||||||
|
- port: {{ .Values.service.port }}
|
||||||
|
targetPort: http
|
||||||
|
protocol: TCP
|
||||||
|
name: http
|
||||||
|
- port: {{ .Values.service.grpcPort }}
|
||||||
|
targetPort: grpc
|
||||||
|
protocol: TCP
|
||||||
|
name: grpc
|
||||||
|
selector:
|
||||||
|
app: {{ template "coupon-api.name" . }}
|
||||||
|
release: {{ .Release.Name }}
|
61
deploy/k8s/helm/coupon-api/values.yaml
Normal file
61
deploy/k8s/helm/coupon-api/values.yaml
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
replicaCount: 1
|
||||||
|
clusterName: eshop-aks
|
||||||
|
pathBase: /coupon-api
|
||||||
|
|
||||||
|
image:
|
||||||
|
repository: eshop/coupon.api
|
||||||
|
tag: latest
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
service:
|
||||||
|
type: ClusterIP
|
||||||
|
port: 80
|
||||||
|
grpcPort: 81
|
||||||
|
|
||||||
|
resources: {}
|
||||||
|
|
||||||
|
nodeSelector: {}
|
||||||
|
|
||||||
|
tolerations: []
|
||||||
|
|
||||||
|
affinity: {}
|
||||||
|
|
||||||
|
# env defines the environment variables that will be declared in the pod
|
||||||
|
env:
|
||||||
|
urls:
|
||||||
|
# configmap declares variables which value is taken from the config map defined in template configmap.yaml (name is name of var and key the key in configmap).
|
||||||
|
configmap:
|
||||||
|
- name: ConnectionString
|
||||||
|
key: coupon__ConnectionString
|
||||||
|
- name: ApplicationInsights__InstrumentationKey
|
||||||
|
key: all__InstrumentationKey
|
||||||
|
- name: EventBusConnection
|
||||||
|
key: all__EventBusConnection
|
||||||
|
- name: AzureServiceBusEnabled
|
||||||
|
key: all__UseAzureServiceBus
|
||||||
|
- name: CouponMongoDatabase
|
||||||
|
key: coupon__MongoDatabase
|
||||||
|
- name: IdentityUrl
|
||||||
|
key: urls__IdentityUrl
|
||||||
|
# values define environment variables with a fixed value (no configmap involved) (name is name of var, and value is its value)
|
||||||
|
values:
|
||||||
|
- name: ASPNETCORE_ENVIRONMENT
|
||||||
|
value: Development
|
||||||
|
- name: OrchestratorType
|
||||||
|
value: "K8S"
|
||||||
|
- name: PORT
|
||||||
|
value: "80"
|
||||||
|
- name: GRPC_PORT
|
||||||
|
value: "81"
|
||||||
|
probes:
|
||||||
|
liveness:
|
||||||
|
path: /liveness
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 15
|
||||||
|
port: 80
|
||||||
|
readiness:
|
||||||
|
path: /hc
|
||||||
|
timeoutSeconds: 5
|
||||||
|
initialDelaySeconds: 90
|
||||||
|
periodSeconds: 60
|
||||||
|
port: 80
|
@ -1,27 +1,27 @@
|
|||||||
Param(
|
Param(
|
||||||
[parameter(Mandatory=$false)][string]$registry,
|
[parameter(Mandatory = $false)][string]$registry,
|
||||||
[parameter(Mandatory=$false)][string]$dockerUser,
|
[parameter(Mandatory = $false)][string]$dockerUser,
|
||||||
[parameter(Mandatory=$false)][string]$dockerPassword,
|
[parameter(Mandatory = $false)][string]$dockerPassword,
|
||||||
[parameter(Mandatory=$false)][string]$externalDns,
|
[parameter(Mandatory = $false)][string]$externalDns,
|
||||||
[parameter(Mandatory=$false)][string]$appName="eshop",
|
[parameter(Mandatory = $false)][string]$appName = "eshop",
|
||||||
[parameter(Mandatory=$false)][bool]$deployInfrastructure=$true,
|
[parameter(Mandatory = $false)][bool]$deployInfrastructure = $true,
|
||||||
[parameter(Mandatory=$false)][bool]$deployCharts=$true,
|
[parameter(Mandatory = $false)][bool]$deployCharts = $true,
|
||||||
[parameter(Mandatory=$false)][bool]$clean=$true,
|
[parameter(Mandatory = $false)][bool]$clean = $true,
|
||||||
[parameter(Mandatory=$false)][string]$aksName="",
|
[parameter(Mandatory = $false)][string]$aksName = "",
|
||||||
[parameter(Mandatory=$false)][string]$aksRg="",
|
[parameter(Mandatory = $false)][string]$aksRg = "",
|
||||||
[parameter(Mandatory=$false)][string]$imageTag="latest",
|
[parameter(Mandatory = $false)][string]$imageTag = "latest",
|
||||||
[parameter(Mandatory=$false)][bool]$useLocalk8s=$false,
|
[parameter(Mandatory = $false)][bool]$useLocalk8s = $false,
|
||||||
[parameter(Mandatory=$false)][bool]$useMesh=$false,
|
[parameter(Mandatory = $false)][bool]$useMesh = $false,
|
||||||
[parameter(Mandatory=$false)][string][ValidateSet('Always','IfNotPresent','Never', IgnoreCase=$false)]$imagePullPolicy="Always",
|
[parameter(Mandatory = $false)][string][ValidateSet('Always', 'IfNotPresent', 'Never', IgnoreCase = $false)]$imagePullPolicy = "Always",
|
||||||
[parameter(Mandatory=$false)][string][ValidateSet('prod','staging','none','custom', IgnoreCase=$false)]$sslSupport = "none",
|
[parameter(Mandatory = $false)][string][ValidateSet('prod', 'staging', 'none', 'custom', IgnoreCase = $false)]$sslSupport = "none",
|
||||||
[parameter(Mandatory=$false)][string]$tlsSecretName = "eshop-tls-custom",
|
[parameter(Mandatory = $false)][string]$tlsSecretName = "eshop-tls-custom",
|
||||||
[parameter(Mandatory=$false)][string]$chartsToDeploy="*",
|
[parameter(Mandatory = $false)][string]$chartsToDeploy = "*",
|
||||||
[parameter(Mandatory=$false)][string]$ingressMeshAnnotationsFile="ingress_values_linkerd.yaml"
|
[parameter(Mandatory = $false)][string]$ingressMeshAnnotationsFile = "ingress_values_linkerd.yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
function Install-Chart {
|
function Install-Chart {
|
||||||
Param([string]$chart,[string]$initialOptions, [bool]$customRegistry)
|
Param([string]$chart, [string]$initialOptions, [bool]$customRegistry)
|
||||||
$options=$initialOptions
|
$options = $initialOptions
|
||||||
if ($sslEnabled) {
|
if ($sslEnabled) {
|
||||||
$options = "$options --set ingress.tls[0].secretName=$tlsSecretName --set ingress.tls[0].hosts={$dns}"
|
$options = "$options --set ingress.tls[0].secretName=$tlsSecretName --set ingress.tls[0].hosts={$dns}"
|
||||||
if ($sslSupport -ne "custom") {
|
if ($sslSupport -ne "custom") {
|
||||||
@ -32,7 +32,8 @@ function Install-Chart {
|
|||||||
$options = "$options --set inf.registry.server=$registry --set inf.registry.login=$dockerUser --set inf.registry.pwd=$dockerPassword --set inf.registry.secretName=eshop-docker-scret"
|
$options = "$options --set inf.registry.server=$registry --set inf.registry.login=$dockerUser --set inf.registry.pwd=$dockerPassword --set inf.registry.secretName=eshop-docker-scret"
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($chart -ne "eshop-common" -or $customRegistry) { # eshop-common is ignored when no secret must be deployed
|
if ($chart -ne "eshop-common" -or $customRegistry) {
|
||||||
|
# eshop-common is ignored when no secret must be deployed
|
||||||
$command = "install $appName-$chart $options $chart"
|
$command = "install $appName-$chart $options $chart"
|
||||||
Write-Host "Helm Command: helm $command" -ForegroundColor Gray
|
Write-Host "Helm Command: helm $command" -ForegroundColor Gray
|
||||||
Invoke-Expression 'cmd /c "helm $command"'
|
Invoke-Expression 'cmd /c "helm $command"'
|
||||||
@ -40,32 +41,32 @@ function Install-Chart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$dns = $externalDns
|
$dns = $externalDns
|
||||||
$sslEnabled=$false
|
$sslEnabled = $false
|
||||||
$sslIssuer=""
|
$sslIssuer = ""
|
||||||
|
|
||||||
if ($sslSupport -eq "staging") {
|
if ($sslSupport -eq "staging") {
|
||||||
$sslEnabled=$true
|
$sslEnabled = $true
|
||||||
$tlsSecretName="eshop-letsencrypt-staging"
|
$tlsSecretName = "eshop-letsencrypt-staging"
|
||||||
$sslIssuer="letsencrypt-staging"
|
$sslIssuer = "letsencrypt-staging"
|
||||||
}
|
}
|
||||||
elseif ($sslSupport -eq "prod") {
|
elseif ($sslSupport -eq "prod") {
|
||||||
$sslEnabled=$true
|
$sslEnabled = $true
|
||||||
$tlsSecretName="eshop-letsencrypt-prod"
|
$tlsSecretName = "eshop-letsencrypt-prod"
|
||||||
$sslIssuer="letsencrypt-prod"
|
$sslIssuer = "letsencrypt-prod"
|
||||||
}
|
}
|
||||||
elseif ($sslSupport -eq "custom") {
|
elseif ($sslSupport -eq "custom") {
|
||||||
$sslEnabled=$true
|
$sslEnabled = $true
|
||||||
}
|
}
|
||||||
|
|
||||||
$ingressValuesFile="ingress_values.yaml"
|
$ingressValuesFile = "ingress_values.yaml"
|
||||||
|
|
||||||
if ($useLocalk8s -eq $true) {
|
if ($useLocalk8s -eq $true) {
|
||||||
$ingressValuesFile="ingress_values_dockerk8s.yaml"
|
$ingressValuesFile = "ingress_values_dockerk8s.yaml"
|
||||||
$dns="localhost"
|
$dns = "localhost"
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($externalDns -eq "aks") {
|
if ($externalDns -eq "aks") {
|
||||||
if ([string]::IsNullOrEmpty($aksName) -or [string]::IsNullOrEmpty($aksRg)) {
|
if ([string]::IsNullOrEmpty($aksName) -or [string]::IsNullOrEmpty($aksRg)) {
|
||||||
Write-Host "Error: When using -dns aks, MUST set -aksName and -aksRg too." -ForegroundColor Red
|
Write-Host "Error: When using -dns aks, MUST set -aksName and -aksRg too." -ForegroundColor Red
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
@ -95,21 +96,22 @@ if ($useLocalk8s -and $sslEnabled) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($clean) {
|
if ($clean) {
|
||||||
$listOfReleases=$(helm ls --filter eshop -q)
|
$listOfReleases = $(helm ls --filter eshop -q)
|
||||||
if ([string]::IsNullOrEmpty($listOfReleases)) {
|
if ([string]::IsNullOrEmpty($listOfReleases)) {
|
||||||
Write-Host "No previous releases found!" -ForegroundColor Green
|
Write-Host "No previous releases found!" -ForegroundColor Green
|
||||||
}else{
|
}
|
||||||
|
else {
|
||||||
Write-Host "Previous releases found" -ForegroundColor Green
|
Write-Host "Previous releases found" -ForegroundColor Green
|
||||||
Write-Host "Cleaning previous helm releases..." -ForegroundColor Green
|
Write-Host "Cleaning previous helm releases..." -ForegroundColor Green
|
||||||
helm uninstall $listOfReleases
|
helm uninstall $listOfReleases
|
||||||
Write-Host "Previous releases deleted" -ForegroundColor Green
|
Write-Host "Previous releases deleted" -ForegroundColor Green
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$useCustomRegistry=$false
|
$useCustomRegistry = $false
|
||||||
|
|
||||||
if (-not [string]::IsNullOrEmpty($registry)) {
|
if (-not [string]::IsNullOrEmpty($registry)) {
|
||||||
$useCustomRegistry=$true
|
$useCustomRegistry = $true
|
||||||
if ([string]::IsNullOrEmpty($dockerUser) -or [string]::IsNullOrEmpty($dockerPassword)) {
|
if ([string]::IsNullOrEmpty($dockerUser) -or [string]::IsNullOrEmpty($dockerPassword)) {
|
||||||
Write-Host "Error: Must use -dockerUser AND -dockerPassword if specifying custom registry" -ForegroundColor Red
|
Write-Host "Error: Must use -dockerUser AND -dockerPassword if specifying custom registry" -ForegroundColor Red
|
||||||
exit 1
|
exit 1
|
||||||
@ -119,7 +121,7 @@ if (-not [string]::IsNullOrEmpty($registry)) {
|
|||||||
Write-Host "Begin eShopOnContainers installation using Helm" -ForegroundColor Green
|
Write-Host "Begin eShopOnContainers installation using Helm" -ForegroundColor Green
|
||||||
|
|
||||||
$infras = ("sql-data", "nosql-data", "rabbitmq", "keystore-data", "basket-data")
|
$infras = ("sql-data", "nosql-data", "rabbitmq", "keystore-data", "basket-data")
|
||||||
$charts = ("eshop-common", "basket-api","catalog-api", "identity-api", "mobileshoppingagg","ordering-api","ordering-backgroundtasks","ordering-signalrhub", "payment-api", "webmvc", "webshoppingagg", "webspa", "webstatus", "webhooks-api", "webhooks-web")
|
$charts = ("eshop-common", "basket-api", "catalog-api", "coupon-api", "identity-api", "mobileshoppingagg", "ordering-api", "ordering-backgroundtasks", "ordering-signalrhub", "payment-api", "webmvc", "webshoppingagg", "webspa", "webstatus", "webhooks-api", "webhooks-web")
|
||||||
$gateways = ("apigwms", "apigwws")
|
$gateways = ("apigwms", "apigwws")
|
||||||
|
|
||||||
if ($deployInfrastructure) {
|
if ($deployInfrastructure) {
|
||||||
|
@ -16,10 +16,12 @@ data:
|
|||||||
webshoppingagg__keystore: {{ .Values.inf.redis.keystore.constr }}
|
webshoppingagg__keystore: {{ .Values.inf.redis.keystore.constr }}
|
||||||
internalurls__basket: http://{{ .Values.app.svc.basket }}
|
internalurls__basket: http://{{ .Values.app.svc.basket }}
|
||||||
internalurls__catalog: http://{{ .Values.app.svc.catalog }}
|
internalurls__catalog: http://{{ .Values.app.svc.catalog }}
|
||||||
|
internalurls__coupon: http://{{ .Values.app.svc.coupon }}
|
||||||
internalurls__identity: http://{{ .Values.app.svc.identity }}
|
internalurls__identity: http://{{ .Values.app.svc.identity }}
|
||||||
internalurls__ordering: http://{{ .Values.app.svc.ordering }}
|
internalurls__ordering: http://{{ .Values.app.svc.ordering }}
|
||||||
internalurls__basket__hc: http://{{ .Values.app.svc.basket }}/hc
|
internalurls__basket__hc: http://{{ .Values.app.svc.basket }}/hc
|
||||||
internalurls__catalog__hc: http://{{ .Values.app.svc.catalog }}/hc
|
internalurls__catalog__hc: http://{{ .Values.app.svc.catalog }}/hc
|
||||||
|
internalurls__coupon__hc: http://{{ .Values.app.svc.coupon }}/hc
|
||||||
internalurls__identity__hc: http://{{ .Values.app.svc.identity }}/hc
|
internalurls__identity__hc: http://{{ .Values.app.svc.identity }}/hc
|
||||||
internalurls__ordering__hc: http://{{ .Values.app.svc.ordering }}/hc
|
internalurls__ordering__hc: http://{{ .Values.app.svc.ordering }}/hc
|
||||||
internalurls__payment__hc: http://{{ .Values.app.svc.payment }}/hc
|
internalurls__payment__hc: http://{{ .Values.app.svc.payment }}/hc
|
||||||
|
@ -43,3 +43,5 @@ data:
|
|||||||
internalurls__payment__hc: http://{{ .Values.app.svc.payment }}/hc
|
internalurls__payment__hc: http://{{ .Values.app.svc.payment }}/hc
|
||||||
name__signalrhub__hc: Ordering SignalR Hub HTTP Check
|
name__signalrhub__hc: Ordering SignalR Hub HTTP Check
|
||||||
internalurls__signalrhub__hc: http://{{ .Values.app.svc.orderingsignalrhub }}/hc
|
internalurls__signalrhub__hc: http://{{ .Values.app.svc.orderingsignalrhub }}/hc
|
||||||
|
name__coupon__hc: Coupon HTTP Check
|
||||||
|
internalurls__coupon__hc: http://{{ .Values.app.svc.coupon }}/hc
|
@ -13,14 +13,11 @@ service:
|
|||||||
|
|
||||||
ingress:
|
ingress:
|
||||||
enabled: true
|
enabled: true
|
||||||
annotations: {
|
annotations: {}
|
||||||
|
|
||||||
}
|
|
||||||
tls: []
|
tls: []
|
||||||
|
|
||||||
resources: {}
|
resources: {}
|
||||||
|
|
||||||
|
|
||||||
nodeSelector: {}
|
nodeSelector: {}
|
||||||
|
|
||||||
tolerations: []
|
tolerations: []
|
||||||
@ -78,10 +75,14 @@ env:
|
|||||||
key: name__orderingbackground__hc
|
key: name__orderingbackground__hc
|
||||||
- name: HealthChecks-UI__HealthChecks__10__Uri
|
- name: HealthChecks-UI__HealthChecks__10__Uri
|
||||||
key: internalurls__orderingbackground__hc
|
key: internalurls__orderingbackground__hc
|
||||||
|
- name: HealthChecks-UI__HealthChecks__11__Name
|
||||||
|
key: name__coupon__hc
|
||||||
|
- name: HealthChecks-UI__HealthChecks__11__Uri
|
||||||
|
key: internalurls__coupon__hc
|
||||||
|
|
||||||
# values define environment variables with a fixed value (no configmap involved) (name is name of var, and value is its value)
|
# values define environment variables with a fixed value (no configmap involved) (name is name of var, and value is its value)
|
||||||
values:
|
values:
|
||||||
- name: ASPNETCORE_ENVIRONMENT
|
- name: ASPNETCORE_ENVIRONMENT
|
||||||
value: Development
|
value: Development
|
||||||
- name: OrchestratorType
|
- name: OrchestratorType
|
||||||
value: 'K8S'
|
value: "K8S"
|
||||||
|
@ -24,6 +24,7 @@ COPY "Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj" "Services/Basket
|
|||||||
COPY "Services/Catalog/Catalog.API/Catalog.API.csproj" "Services/Catalog/Catalog.API/Catalog.API.csproj"
|
COPY "Services/Catalog/Catalog.API/Catalog.API.csproj" "Services/Catalog/Catalog.API/Catalog.API.csproj"
|
||||||
COPY "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj" "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj"
|
COPY "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj" "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj"
|
||||||
COPY "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj" "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj"
|
COPY "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj" "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj"
|
||||||
|
COPY "Services/Coupon/Coupon.API/Coupon.API.csproj" "Services/Coupon/Coupon.API/Coupon.API.csproj"
|
||||||
COPY "Services/Identity/Identity.API/Identity.API.csproj" "Services/Identity/Identity.API/Identity.API.csproj"
|
COPY "Services/Identity/Identity.API/Identity.API.csproj" "Services/Identity/Identity.API/Identity.API.csproj"
|
||||||
COPY "Services/Ordering/Ordering.API/Ordering.API.csproj" "Services/Ordering/Ordering.API/Ordering.API.csproj"
|
COPY "Services/Ordering/Ordering.API/Ordering.API.csproj" "Services/Ordering/Ordering.API/Ordering.API.csproj"
|
||||||
COPY "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj" "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj"
|
COPY "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj" "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj"
|
||||||
|
@ -24,6 +24,7 @@ COPY "Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj" "Services/Basket
|
|||||||
COPY "Services/Catalog/Catalog.API/Catalog.API.csproj" "Services/Catalog/Catalog.API/Catalog.API.csproj"
|
COPY "Services/Catalog/Catalog.API/Catalog.API.csproj" "Services/Catalog/Catalog.API/Catalog.API.csproj"
|
||||||
COPY "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj" "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj"
|
COPY "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj" "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj"
|
||||||
COPY "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj" "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj"
|
COPY "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj" "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj"
|
||||||
|
COPY "Services/Coupon/Coupon.API/Coupon.API.csproj" "Services/Coupon/Coupon.API/Coupon.API.csproj"
|
||||||
COPY "Services/Identity/Identity.API/Identity.API.csproj" "Services/Identity/Identity.API/Identity.API.csproj"
|
COPY "Services/Identity/Identity.API/Identity.API.csproj" "Services/Identity/Identity.API/Identity.API.csproj"
|
||||||
COPY "Services/Ordering/Ordering.API/Ordering.API.csproj" "Services/Ordering/Ordering.API/Ordering.API.csproj"
|
COPY "Services/Ordering/Ordering.API/Ordering.API.csproj" "Services/Ordering/Ordering.API/Ordering.API.csproj"
|
||||||
COPY "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj" "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj"
|
COPY "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj" "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj"
|
||||||
|
@ -24,6 +24,7 @@ COPY "Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj" "Services/Basket
|
|||||||
COPY "Services/Catalog/Catalog.API/Catalog.API.csproj" "Services/Catalog/Catalog.API/Catalog.API.csproj"
|
COPY "Services/Catalog/Catalog.API/Catalog.API.csproj" "Services/Catalog/Catalog.API/Catalog.API.csproj"
|
||||||
COPY "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj" "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj"
|
COPY "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj" "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj"
|
||||||
COPY "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj" "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj"
|
COPY "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj" "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj"
|
||||||
|
COPY "Services/Coupon/Coupon.API/Coupon.API.csproj" "Services/Coupon/Coupon.API/Coupon.API.csproj"
|
||||||
COPY "Services/Identity/Identity.API/Identity.API.csproj" "Services/Identity/Identity.API/Identity.API.csproj"
|
COPY "Services/Identity/Identity.API/Identity.API.csproj" "Services/Identity/Identity.API/Identity.API.csproj"
|
||||||
COPY "Services/Ordering/Ordering.API/Ordering.API.csproj" "Services/Ordering/Ordering.API/Ordering.API.csproj"
|
COPY "Services/Ordering/Ordering.API/Ordering.API.csproj" "Services/Ordering/Ordering.API/Ordering.API.csproj"
|
||||||
COPY "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj" "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj"
|
COPY "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj" "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj"
|
||||||
|
@ -25,6 +25,7 @@ COPY "Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj" "Services/Basket
|
|||||||
COPY "Services/Catalog/Catalog.API/Catalog.API.csproj" "Services/Catalog/Catalog.API/Catalog.API.csproj"
|
COPY "Services/Catalog/Catalog.API/Catalog.API.csproj" "Services/Catalog/Catalog.API/Catalog.API.csproj"
|
||||||
COPY "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj" "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj"
|
COPY "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj" "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj"
|
||||||
COPY "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj" "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj"
|
COPY "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj" "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj"
|
||||||
|
COPY "Services/Coupon/Coupon.API/Coupon.API.csproj" "Services/Coupon/Coupon.API/Coupon.API.csproj"
|
||||||
COPY "Services/Identity/Identity.API/Identity.API.csproj" "Services/Identity/Identity.API/Identity.API.csproj"
|
COPY "Services/Identity/Identity.API/Identity.API.csproj" "Services/Identity/Identity.API/Identity.API.csproj"
|
||||||
COPY "Services/Ordering/Ordering.API/Ordering.API.csproj" "Services/Ordering/Ordering.API/Ordering.API.csproj"
|
COPY "Services/Ordering/Ordering.API/Ordering.API.csproj" "Services/Ordering/Ordering.API/Ordering.API.csproj"
|
||||||
COPY "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj" "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj"
|
COPY "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj" "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj"
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
namespace Coupon.API.Controllers;
|
||||||
|
|
||||||
|
[Authorize]
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/v1/[controller]")]
|
||||||
|
public class CouponController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly ICouponRepository _couponRepository;
|
||||||
|
|
||||||
|
public CouponController(ICouponRepository couponRepository)
|
||||||
|
{
|
||||||
|
_couponRepository = couponRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{code}")]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
public async Task<ActionResult<Infrastructure.Models.Coupon>> GetCouponByCodeAsync(string code)
|
||||||
|
{
|
||||||
|
var coupon = await _couponRepository.FindCouponByCodeAsync(code);
|
||||||
|
|
||||||
|
if (coupon is null || coupon.Consumed)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
return coupon;
|
||||||
|
}
|
||||||
|
}
|
63
src/Services/Coupon/Coupon.API/Coupon.API.csproj
Normal file
63
src/Services/Coupon/Coupon.API/Coupon.API.csproj
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<UserSecretsId>1d5bc948-90f1-4906-a1f8-8edaa1ed9e2e</UserSecretsId>
|
||||||
|
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||||
|
<DockerfileContext>..\..\..\..</DockerfileContext>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Remove="C:\Users\Siarhei_Sialitski\.nuget\packages\mongodb.driver.core\2.13.3\contentFiles\any\netstandard2.1\Core\Compression\Snappy\lib\win\snappy32.dll" />
|
||||||
|
<Content Remove="C:\Users\Siarhei_Sialitski\.nuget\packages\mongodb.driver.core\2.13.3\contentFiles\any\netstandard2.1\Core\Compression\Snappy\lib\win\snappy64.dll" />
|
||||||
|
<Content Remove="C:\Users\Siarhei_Sialitski\.nuget\packages\mongodb.driver.core\2.13.3\contentFiles\any\netstandard2.1\Core\Compression\Zstandard\lib\win\libzstd.dll" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="AspNetCore.HealthChecks.AzureServiceBus" Version="6.0.3" />
|
||||||
|
<PackageReference Include="AspNetCore.HealthChecks.MongoDb" Version="6.0.1" />
|
||||||
|
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="6.0.2" />
|
||||||
|
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="6.0.2" />
|
||||||
|
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="6.0.4" />
|
||||||
|
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="7.2.0" />
|
||||||
|
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.20.0" />
|
||||||
|
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="2.0.2" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.3" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="3.1.23" />
|
||||||
|
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.15.0" />
|
||||||
|
<PackageReference Include="MongoDB.Driver.Core" Version="2.13.3" />
|
||||||
|
<PackageReference Include="Polly" Version="7.2.3" />
|
||||||
|
<PackageReference Include="Serilog.AspNetCore" Version="5.0.0" />
|
||||||
|
<PackageReference Include="Serilog.Settings.Configuration" Version="3.3.0" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Http" Version="7.2.0" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Seq" Version="5.1.1" />
|
||||||
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.3.0" />
|
||||||
|
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.16.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBus\EventBus.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\IntegrationEventLogEF\IntegrationEventLogEF.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Remove="C:\Users\Siarhei_Sialitski\.nuget\packages\mongodb.driver.core\2.13.3\build\../runtimes/win/native/snappy32.dll" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Remove="C:\Users\Siarhei_Sialitski\.nuget\packages\mongodb.driver.core\2.13.3\build\../runtimes/win/native/snappy64.dll" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Remove="C:\Users\Siarhei_Sialitski\.nuget\packages\mongodb.driver.core\2.13.3\build\../runtimes/win/native/snappy64.dll" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Remove="C:\Users\Siarhei_Sialitski\.nuget\packages\mongodb.driver.core\2.13.3\build\../runtimes/win/native/libzstd.dll" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
|
</Project>
|
15
src/Services/Coupon/Coupon.API/CouponSettings.cs
Normal file
15
src/Services/Coupon/Coupon.API/CouponSettings.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
namespace Coupon.API
|
||||||
|
{
|
||||||
|
public class CouponSettings
|
||||||
|
{
|
||||||
|
public string ConnectionString { get; set; }
|
||||||
|
|
||||||
|
public string CouponMongoDatabase { get; set; }
|
||||||
|
|
||||||
|
public string EventBusConnection { get; set; }
|
||||||
|
|
||||||
|
public bool UseCustomizationData { get; set; }
|
||||||
|
|
||||||
|
public bool AzureStorageEnabled { get; set; }
|
||||||
|
}
|
||||||
|
}
|
62
src/Services/Coupon/Coupon.API/Dockerfile
Normal file
62
src/Services/Coupon/Coupon.API/Dockerfile
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
|
||||||
|
|
||||||
|
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
|
||||||
|
WORKDIR /app
|
||||||
|
EXPOSE 80
|
||||||
|
EXPOSE 443
|
||||||
|
|
||||||
|
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
|
||||||
|
WORKDIR /src
|
||||||
|
|
||||||
|
# It's important to keep lines from here down to "COPY . ." identical in all Dockerfiles
|
||||||
|
# to take advantage of Docker's build cache, to speed up local container builds
|
||||||
|
COPY "eShopOnContainers-ServicesAndWebApps.sln" "eShopOnContainers-ServicesAndWebApps.sln"
|
||||||
|
|
||||||
|
COPY "ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj" "ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj"
|
||||||
|
COPY "ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj" "ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj"
|
||||||
|
COPY "BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj" "BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj"
|
||||||
|
COPY "BuildingBlocks/EventBus/EventBus/EventBus.csproj" "BuildingBlocks/EventBus/EventBus/EventBus.csproj"
|
||||||
|
COPY "BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj" "BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj"
|
||||||
|
COPY "BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj" "BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj"
|
||||||
|
COPY "BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj" "BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj"
|
||||||
|
COPY "BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj" "BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj"
|
||||||
|
COPY "BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj" "BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj"
|
||||||
|
COPY "Services/Basket/Basket.API/Basket.API.csproj" "Services/Basket/Basket.API/Basket.API.csproj"
|
||||||
|
COPY "Services/Basket/Basket.FunctionalTests/Basket.FunctionalTests.csproj" "Services/Basket/Basket.FunctionalTests/Basket.FunctionalTests.csproj"
|
||||||
|
COPY "Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj" "Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj"
|
||||||
|
COPY "Services/Catalog/Catalog.API/Catalog.API.csproj" "Services/Catalog/Catalog.API/Catalog.API.csproj"
|
||||||
|
COPY "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj" "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj"
|
||||||
|
COPY "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj" "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj"
|
||||||
|
COPY "Services/Coupon/Coupon.API/Coupon.API.csproj" "Services/Coupon/Coupon.API/Coupon.API.csproj"
|
||||||
|
COPY "Services/Identity/Identity.API/Identity.API.csproj" "Services/Identity/Identity.API/Identity.API.csproj"
|
||||||
|
COPY "Services/Ordering/Ordering.API/Ordering.API.csproj" "Services/Ordering/Ordering.API/Ordering.API.csproj"
|
||||||
|
COPY "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj" "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj"
|
||||||
|
COPY "Services/Ordering/Ordering.Domain/Ordering.Domain.csproj" "Services/Ordering/Ordering.Domain/Ordering.Domain.csproj"
|
||||||
|
COPY "Services/Ordering/Ordering.FunctionalTests/Ordering.FunctionalTests.csproj" "Services/Ordering/Ordering.FunctionalTests/Ordering.FunctionalTests.csproj"
|
||||||
|
COPY "Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj" "Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj"
|
||||||
|
COPY "Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj" "Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj"
|
||||||
|
COPY "Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj" "Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj"
|
||||||
|
COPY "Services/Payment/Payment.API/Payment.API.csproj" "Services/Payment/Payment.API/Payment.API.csproj"
|
||||||
|
COPY "Services/Webhooks/Webhooks.API/Webhooks.API.csproj" "Services/Webhooks/Webhooks.API/Webhooks.API.csproj"
|
||||||
|
COPY "Tests/Services/Application.FunctionalTests/Application.FunctionalTests.csproj" "Tests/Services/Application.FunctionalTests/Application.FunctionalTests.csproj"
|
||||||
|
COPY "Web/WebhookClient/WebhookClient.csproj" "Web/WebhookClient/WebhookClient.csproj"
|
||||||
|
COPY "Web/WebMVC/WebMVC.csproj" "Web/WebMVC/WebMVC.csproj"
|
||||||
|
COPY "Web/WebSPA/WebSPA.csproj" "Web/WebSPA/WebSPA.csproj"
|
||||||
|
COPY "Web/WebStatus/WebStatus.csproj" "Web/WebStatus/WebStatus.csproj"
|
||||||
|
|
||||||
|
COPY "docker-compose.dcproj" "docker-compose.dcproj"
|
||||||
|
|
||||||
|
COPY "NuGet.config" "NuGet.config"
|
||||||
|
|
||||||
|
RUN dotnet restore "eShopOnContainers-ServicesAndWebApps.sln"
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
WORKDIR "/src/Services/Coupon/Coupon.API"
|
||||||
|
|
||||||
|
FROM build AS publish
|
||||||
|
RUN dotnet publish "Coupon.API.csproj" -c Release -o /app/publish
|
||||||
|
|
||||||
|
FROM base AS final
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=publish /app/publish .
|
||||||
|
ENTRYPOINT ["dotnet", "Coupon.API.dll"]
|
@ -0,0 +1,49 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.Data.SqlClient;
|
||||||
|
using Coupon.API.IntegrationEvents.EventHandlers;
|
||||||
|
using Coupon.API.IntegrationEvents.Events;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Polly;
|
||||||
|
|
||||||
|
namespace Coupon.API.Extensions
|
||||||
|
{
|
||||||
|
public static class IHostBuilderExtensions
|
||||||
|
{
|
||||||
|
public static IHost SeedDatabaseStrategy<TContext>(this IHost host, Action<TContext> seeder)
|
||||||
|
{
|
||||||
|
using (var scope = host.Services.CreateScope())
|
||||||
|
{
|
||||||
|
var context = scope.ServiceProvider.GetService<TContext>();
|
||||||
|
|
||||||
|
var policy = Policy.Handle<SqlException>()
|
||||||
|
.WaitAndRetry(new TimeSpan[]
|
||||||
|
{
|
||||||
|
TimeSpan.FromSeconds(3),
|
||||||
|
TimeSpan.FromSeconds(5),
|
||||||
|
TimeSpan.FromSeconds(8),
|
||||||
|
});
|
||||||
|
|
||||||
|
policy.Execute(() =>
|
||||||
|
{
|
||||||
|
seeder.Invoke(context);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IHost SubscribersIntegrationEvents(this IHost host)
|
||||||
|
{
|
||||||
|
using (var scope = host.Services.CreateScope())
|
||||||
|
{
|
||||||
|
var eventBus = scope.ServiceProvider.GetRequiredService<IEventBus>();
|
||||||
|
|
||||||
|
eventBus.Subscribe<OrderStatusChangedToAwaitingCouponValidationIntegrationEvent, OrderStatusChangedToAwaitingCouponValidationIntegrationEventHandler>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,204 @@
|
|||||||
|
namespace Coupon.API.Extensions;
|
||||||
|
|
||||||
|
public static class IServiceCollectionExtensions
|
||||||
|
{
|
||||||
|
public static IServiceCollection AddCouponRegister(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
services.AddTransient<ICouponRepository, CouponRepository>()
|
||||||
|
.AddTransient<IServiceBusPersisterConnection, DefaultServiceBusPersisterConnection>(service =>
|
||||||
|
{
|
||||||
|
var settings = service.GetRequiredService<IOptions<CouponSettings>>().Value;
|
||||||
|
var serviceBusConnection = settings.EventBusConnection;
|
||||||
|
|
||||||
|
return new DefaultServiceBusPersisterConnection(serviceBusConnection);
|
||||||
|
})
|
||||||
|
.AddTransient<IRabbitMQPersistentConnection, DefaultRabbitMQPersistentConnection>(service =>
|
||||||
|
{
|
||||||
|
var factory = new ConnectionFactory()
|
||||||
|
{
|
||||||
|
HostName = configuration["EventBusConnection"],
|
||||||
|
DispatchConsumersAsync = true
|
||||||
|
};
|
||||||
|
|
||||||
|
var retryCount = 5;
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(configuration["EventBusRetryCount"]))
|
||||||
|
{
|
||||||
|
retryCount = int.Parse(configuration["EventBusRetryCount"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DefaultRabbitMQPersistentConnection(factory, service.GetService<ILogger<DefaultRabbitMQPersistentConnection>>(), retryCount);
|
||||||
|
})
|
||||||
|
.AddTransient<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>()
|
||||||
|
.AddTransient<CouponContext>();
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddSwagger(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
services.AddSwaggerGen(options =>
|
||||||
|
{
|
||||||
|
options.SwaggerDoc("v1", new OpenApiInfo
|
||||||
|
{
|
||||||
|
Title = "eShopOnContainers - Coupon HTTP API",
|
||||||
|
Version = "v1",
|
||||||
|
Description = "The Coupon Service HTTP API"
|
||||||
|
});
|
||||||
|
|
||||||
|
options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
|
||||||
|
{
|
||||||
|
Type = SecuritySchemeType.OAuth2,
|
||||||
|
Flows = new OpenApiOAuthFlows()
|
||||||
|
{
|
||||||
|
Implicit = new OpenApiOAuthFlow()
|
||||||
|
{
|
||||||
|
AuthorizationUrl = new Uri($"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/authorize"),
|
||||||
|
TokenUrl = new Uri($"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/token"),
|
||||||
|
Scopes = new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
{ "coupon", "Coupon API" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
options.OperationFilter<AuthorizeCheckOperationFilter>();
|
||||||
|
});
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddCustomSettings(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
services.Configure<CouponSettings>(configuration);
|
||||||
|
services.Configure<ApiBehaviorOptions>(options =>
|
||||||
|
{
|
||||||
|
options.InvalidModelStateResponseFactory = context =>
|
||||||
|
{
|
||||||
|
var problemDetails = new ValidationProblemDetails(context.ModelState)
|
||||||
|
{
|
||||||
|
Instance = context.HttpContext.Request.Path,
|
||||||
|
Status = StatusCodes.Status400BadRequest,
|
||||||
|
Detail = "Please refer to the errors property for additional details."
|
||||||
|
};
|
||||||
|
|
||||||
|
return new BadRequestObjectResult(problemDetails)
|
||||||
|
{
|
||||||
|
ContentTypes = { "application/problem+json", "application/problem+xml" }
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddEventBus(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
var subscriptionClientName = configuration["SubscriptionClientName"];
|
||||||
|
|
||||||
|
if (configuration.GetValue<bool>("AzureServiceBusEnabled"))
|
||||||
|
{
|
||||||
|
services.AddSingleton<IEventBus, EventBusServiceBus>(sp =>
|
||||||
|
{
|
||||||
|
var serviceBusPersisterConnection = sp.GetRequiredService<IServiceBusPersisterConnection>();
|
||||||
|
var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>();
|
||||||
|
var logger = sp.GetRequiredService<ILogger<EventBusServiceBus>>();
|
||||||
|
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();
|
||||||
|
|
||||||
|
return new EventBusServiceBus(serviceBusPersisterConnection, logger, eventBusSubcriptionsManager, iLifetimeScope, subscriptionClientName);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
services.AddSingleton<IEventBus, EventBusRabbitMQ>(sp =>
|
||||||
|
{
|
||||||
|
var rabbitMQPersistentConnection = sp.GetRequiredService<IRabbitMQPersistentConnection>();
|
||||||
|
var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>();
|
||||||
|
var logger = sp.GetRequiredService<ILogger<EventBusRabbitMQ>>();
|
||||||
|
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();
|
||||||
|
|
||||||
|
var retryCount = 5;
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(configuration["EventBusRetryCount"]))
|
||||||
|
{
|
||||||
|
retryCount = int.Parse(configuration["EventBusRetryCount"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddCustomHealthCheck(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
var accountName = configuration.GetValue<string>("AzureStorageAccountName");
|
||||||
|
var accountKey = configuration.GetValue<string>("AzureStorageAccountKey");
|
||||||
|
|
||||||
|
var hcBuilder = services.AddHealthChecks();
|
||||||
|
|
||||||
|
hcBuilder.AddCheck("self", () => HealthCheckResult.Healthy())
|
||||||
|
.AddMongoDb(
|
||||||
|
configuration["ConnectionString"],
|
||||||
|
name: "CouponCollection-check",
|
||||||
|
tags: new string[] { "couponcollection" });
|
||||||
|
|
||||||
|
if (configuration.GetValue<bool>("AzureServiceBusEnabled"))
|
||||||
|
{
|
||||||
|
hcBuilder.AddAzureServiceBusTopic(
|
||||||
|
configuration["EventBusConnection"],
|
||||||
|
topicName: "eshop_event_bus",
|
||||||
|
name: "coupon-servicebus-check",
|
||||||
|
tags: new string[] { "servicebus" });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hcBuilder.AddRabbitMQ(
|
||||||
|
$"amqp://{configuration["EventBusConnection"]}",
|
||||||
|
name: "coupon-rabbitmqbus-check",
|
||||||
|
tags: new string[] { "rabbitmqbus" });
|
||||||
|
}
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddCustomPolicies(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddCors(options =>
|
||||||
|
{
|
||||||
|
options.AddPolicy("CorsPolicy",
|
||||||
|
builder => builder.SetIsOriginAllowed((host) => true)
|
||||||
|
.AllowAnyMethod()
|
||||||
|
.AllowAnyHeader()
|
||||||
|
.AllowCredentials());
|
||||||
|
});
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddAppInsights(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
services.AddApplicationInsightsTelemetry(configuration);
|
||||||
|
services.AddApplicationInsightsKubernetesEnricher();
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
return services.AddAuthentication(options =>
|
||||||
|
{
|
||||||
|
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
|
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
|
}).AddJwtBearer(options =>
|
||||||
|
{
|
||||||
|
options.Authority = configuration["IdentityUrl"];
|
||||||
|
options.RequireHttpsMetadata = false;
|
||||||
|
options.Audience = "coupon";
|
||||||
|
}).Services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddCustomAuthorization(this IServiceCollection services) => services.AddAuthorization();
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.OpenApi.Models;
|
||||||
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
|
|
||||||
|
namespace Coupon.API.Filters
|
||||||
|
{
|
||||||
|
public class AuthorizeCheckOperationFilter : IOperationFilter
|
||||||
|
{
|
||||||
|
public void Apply(OpenApiOperation operation, OperationFilterContext context)
|
||||||
|
{
|
||||||
|
var hasAuthorize = context.MethodInfo.DeclaringType.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any() ||
|
||||||
|
context.MethodInfo.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any();
|
||||||
|
|
||||||
|
if (!hasAuthorize) return;
|
||||||
|
|
||||||
|
operation.Responses.TryAdd("401", new OpenApiResponse { Description = "Unauthorized" });
|
||||||
|
operation.Responses.TryAdd("403", new OpenApiResponse { Description = "Forbidden" });
|
||||||
|
|
||||||
|
var oAuthScheme = new OpenApiSecurityScheme
|
||||||
|
{
|
||||||
|
Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" }
|
||||||
|
};
|
||||||
|
|
||||||
|
operation.Security = new List<OpenApiSecurityRequirement>
|
||||||
|
{
|
||||||
|
new OpenApiSecurityRequirement
|
||||||
|
{
|
||||||
|
[oAuthScheme] = new [] { "CouponApi" }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
|
||||||
|
namespace Coupon.API.Filters
|
||||||
|
{
|
||||||
|
public class ValidateModelAttribute : ActionFilterAttribute
|
||||||
|
{
|
||||||
|
public override void OnActionExecuting(ActionExecutingContext context)
|
||||||
|
{
|
||||||
|
if (!context.ModelState.IsValid)
|
||||||
|
{
|
||||||
|
context.Result = new BadRequestObjectResult(context.ModelState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
33
src/Services/Coupon/Coupon.API/GlobalUsings.cs
Normal file
33
src/Services/Coupon/Coupon.API/GlobalUsings.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
global using Coupon.API.Filters;
|
||||||
|
global using Coupon.API.Infrastructure.Repositories;
|
||||||
|
global using Coupon.API.Infrastructure.Models;
|
||||||
|
global using Autofac.Extensions.DependencyInjection;
|
||||||
|
global using Autofac;
|
||||||
|
global using Microsoft.AspNetCore.Authorization;
|
||||||
|
global using Microsoft.AspNetCore.Hosting;
|
||||||
|
global using Microsoft.AspNetCore.Http;
|
||||||
|
global using Microsoft.AspNetCore.Builder;
|
||||||
|
global using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
global using Microsoft.AspNetCore.Mvc;
|
||||||
|
global using Microsoft.Extensions.Logging;
|
||||||
|
global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
|
global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
||||||
|
global using Microsoft.Extensions.Configuration;
|
||||||
|
global using Microsoft.Extensions.DependencyInjection;
|
||||||
|
global using Microsoft.Extensions.Hosting;
|
||||||
|
global using Microsoft.Extensions.Options;
|
||||||
|
global using Polly;
|
||||||
|
global using Serilog.Context;
|
||||||
|
global using Serilog;
|
||||||
|
global using System.Collections.Generic;
|
||||||
|
global using System.IO;
|
||||||
|
global using System.Linq;
|
||||||
|
global using System.Threading.Tasks;
|
||||||
|
global using System;
|
||||||
|
global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus;
|
||||||
|
global using Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ;
|
||||||
|
global using Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus;
|
||||||
|
global using Microsoft.Extensions.Diagnostics.HealthChecks;
|
||||||
|
global using Microsoft.OpenApi.Models;
|
||||||
|
global using RabbitMQ.Client;
|
||||||
|
global using Microsoft.AspNetCore.Authentication.JwtBearer;
|
52
src/Services/Coupon/Coupon.API/Infrastructure/CouponSeed.cs
Normal file
52
src/Services/Coupon/Coupon.API/Infrastructure/CouponSeed.cs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
namespace Coupon.API.Infrastructure
|
||||||
|
{
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Coupon.API.Infrastructure.Models;
|
||||||
|
using Coupon.API.Infrastructure.Repositories;
|
||||||
|
|
||||||
|
public class CouponSeed
|
||||||
|
{
|
||||||
|
public async Task SeedAsync(CouponContext context)
|
||||||
|
{
|
||||||
|
if (context.Coupons.EstimatedDocumentCount() == 0)
|
||||||
|
{
|
||||||
|
var coupons = new List<Coupon>
|
||||||
|
{
|
||||||
|
new Coupon
|
||||||
|
{
|
||||||
|
Code = "DISC-5",
|
||||||
|
Discount = 5
|
||||||
|
},
|
||||||
|
new Coupon
|
||||||
|
{
|
||||||
|
Code = "DISC-10",
|
||||||
|
Discount = 10
|
||||||
|
},
|
||||||
|
new Coupon
|
||||||
|
{
|
||||||
|
Code = "DISC-15",
|
||||||
|
Discount = 15
|
||||||
|
},
|
||||||
|
new Coupon
|
||||||
|
{
|
||||||
|
Code = "DISC-20",
|
||||||
|
Discount = 20
|
||||||
|
},
|
||||||
|
new Coupon
|
||||||
|
{
|
||||||
|
Code = "DISC-25",
|
||||||
|
Discount = 25
|
||||||
|
},
|
||||||
|
new Coupon
|
||||||
|
{
|
||||||
|
Code = "DISC-30",
|
||||||
|
Discount = 30
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
await context.Coupons.InsertManyAsync(coupons);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
using MongoDB.Bson;
|
||||||
|
using MongoDB.Bson.Serialization.Attributes;
|
||||||
|
|
||||||
|
namespace Coupon.API.Infrastructure.Models
|
||||||
|
{
|
||||||
|
public class Coupon
|
||||||
|
{
|
||||||
|
[BsonIgnoreIfDefault]
|
||||||
|
[BsonRepresentation(BsonType.ObjectId)]
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
public int Discount { get; set; }
|
||||||
|
|
||||||
|
public string Code { get; set; }
|
||||||
|
|
||||||
|
public bool Consumed { get; set; }
|
||||||
|
|
||||||
|
public int OrderId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
namespace Coupon.API.Infrastructure.Repositories
|
||||||
|
{
|
||||||
|
using Coupon.API.Infrastructure.Models;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
|
||||||
|
public class CouponContext
|
||||||
|
{
|
||||||
|
private readonly IMongoDatabase _database = null;
|
||||||
|
|
||||||
|
public CouponContext(IOptions<CouponSettings> settings)
|
||||||
|
{
|
||||||
|
var client = new MongoClient(settings.Value.ConnectionString);
|
||||||
|
|
||||||
|
if (client is null)
|
||||||
|
{
|
||||||
|
throw new MongoConfigurationException("Cannot connect to the database. The connection string is not valid or the database is not accessible");
|
||||||
|
}
|
||||||
|
|
||||||
|
_database = client.GetDatabase(settings.Value.CouponMongoDatabase);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IMongoCollection<Coupon> Coupons => _database.GetCollection<Coupon>("CouponCollection");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
namespace Coupon.API.Infrastructure.Repositories
|
||||||
|
{
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Coupon.API.Infrastructure.Models;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
|
||||||
|
public class CouponRepository : ICouponRepository
|
||||||
|
{
|
||||||
|
private readonly CouponContext _couponContext;
|
||||||
|
|
||||||
|
public CouponRepository(CouponContext couponContext)
|
||||||
|
{
|
||||||
|
_couponContext = couponContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateCouponConsumedByCodeAsync(string code, int orderId)
|
||||||
|
{
|
||||||
|
var filter = Builders<Coupon>.Filter.Eq("Code", code);
|
||||||
|
var update = Builders<Coupon>.Update
|
||||||
|
.Set(coupon => coupon.Consumed, true)
|
||||||
|
.Set(coupon => coupon.OrderId, orderId);
|
||||||
|
|
||||||
|
await _couponContext.Coupons.UpdateOneAsync(filter, update, new UpdateOptions { IsUpsert = false });
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateCouponReleasedByOrderIdAsync(int orderId)
|
||||||
|
{
|
||||||
|
var filter = Builders<Coupon>.Filter.Eq("OrderId", orderId);
|
||||||
|
var update = Builders<Coupon>.Update
|
||||||
|
.Set(coupon => coupon.Consumed, false)
|
||||||
|
.Set(coupon => coupon.OrderId, 0);
|
||||||
|
|
||||||
|
await _couponContext.Coupons.UpdateOneAsync(filter, update, new UpdateOptions { IsUpsert = false });
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Coupon> FindCouponByCodeAsync(string code)
|
||||||
|
{
|
||||||
|
var filter = Builders<Coupon>.Filter.Eq("Code", code);
|
||||||
|
return await _couponContext.Coupons.Find(filter).FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
namespace Coupon.API.Infrastructure.Repositories
|
||||||
|
{
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Coupon.API.Infrastructure.Models;
|
||||||
|
|
||||||
|
public interface ICouponRepository
|
||||||
|
{
|
||||||
|
Task<Coupon> FindCouponByCodeAsync(string code);
|
||||||
|
|
||||||
|
Task UpdateCouponConsumedByCodeAsync(string code, int orderId);
|
||||||
|
|
||||||
|
Task UpdateCouponReleasedByOrderIdAsync(int orderId);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using Coupon.API.Infrastructure.Repositories;
|
||||||
|
using Coupon.API.IntegrationEvents.Events;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
||||||
|
using Serilog;
|
||||||
|
using Serilog.Context;
|
||||||
|
|
||||||
|
namespace Coupon.API.IntegrationEvents.EventHandlers
|
||||||
|
{
|
||||||
|
public class OrderStatusChangedToAwaitingCouponValidationIntegrationEventHandler : IIntegrationEventHandler<OrderStatusChangedToAwaitingCouponValidationIntegrationEvent>
|
||||||
|
{
|
||||||
|
private readonly ICouponRepository _couponRepository;
|
||||||
|
private readonly IEventBus _eventBus;
|
||||||
|
|
||||||
|
public OrderStatusChangedToAwaitingCouponValidationIntegrationEventHandler(ICouponRepository couponRepository, IEventBus eventBus)
|
||||||
|
{
|
||||||
|
_couponRepository = couponRepository;
|
||||||
|
_eventBus = eventBus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Handle(OrderStatusChangedToAwaitingCouponValidationIntegrationEvent @event)
|
||||||
|
{
|
||||||
|
await Task.Delay(3000);
|
||||||
|
|
||||||
|
using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-Coupon.API"))
|
||||||
|
{
|
||||||
|
Log.Information("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, "Coupon.API", @event);
|
||||||
|
|
||||||
|
var couponIntegrationEvent = await ProcessIntegrationEventAsync(@event);
|
||||||
|
|
||||||
|
Log.Information("----- Publishing integration event: {IntegrationEventId} from {AppName} - ({@IntegrationEvent})", couponIntegrationEvent.Id, "Coupon.API", couponIntegrationEvent);
|
||||||
|
|
||||||
|
_eventBus.Publish(couponIntegrationEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<IntegrationEvent> ProcessIntegrationEventAsync(OrderStatusChangedToAwaitingCouponValidationIntegrationEvent integrationEvent)
|
||||||
|
{
|
||||||
|
var coupon = await _couponRepository.FindCouponByCodeAsync(integrationEvent.Code);
|
||||||
|
|
||||||
|
Log.Information("----- Coupon \"{CouponCode}\": {@Coupon}", integrationEvent.Code, coupon);
|
||||||
|
|
||||||
|
if (coupon == null || coupon.Consumed)
|
||||||
|
{
|
||||||
|
return new OrderCouponRejectedIntegrationEvent(integrationEvent.OrderId, coupon.Code);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.Information("Consumed coupon: {DiscountCode}", integrationEvent.Code);
|
||||||
|
|
||||||
|
await _couponRepository.UpdateCouponConsumedByCodeAsync(integrationEvent.Code, integrationEvent.OrderId);
|
||||||
|
|
||||||
|
return new OrderCouponConfirmedIntegrationEvent(integrationEvent.OrderId, coupon.Discount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using Coupon.API.Infrastructure.Repositories;
|
||||||
|
using Coupon.API.IntegrationEvents.Events;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
|
|
||||||
|
namespace Coupon.API.IntegrationEvents.EventHandlers
|
||||||
|
{
|
||||||
|
public class OrderStatusChangedToCancelledIntegrationEventHandler : IIntegrationEventHandler<OrderStatusChangedToCancelledIntegrationEvent>
|
||||||
|
{
|
||||||
|
private readonly ICouponRepository _couponRepository;
|
||||||
|
|
||||||
|
public OrderStatusChangedToCancelledIntegrationEventHandler(ICouponRepository couponRepository)
|
||||||
|
{
|
||||||
|
_couponRepository = couponRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Handle(OrderStatusChangedToCancelledIntegrationEvent @event)
|
||||||
|
{
|
||||||
|
await _couponRepository.UpdateCouponReleasedByOrderIdAsync(@event.OrderId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
namespace Coupon.API.IntegrationEvents.Events;
|
||||||
|
|
||||||
|
public record OrderCouponConfirmedIntegrationEvent : IntegrationEvent
|
||||||
|
{
|
||||||
|
public int OrderId { get; }
|
||||||
|
|
||||||
|
public int Discount { get; }
|
||||||
|
|
||||||
|
public OrderCouponConfirmedIntegrationEvent(int orderId, int discount)
|
||||||
|
{
|
||||||
|
OrderId = orderId;
|
||||||
|
Discount = discount;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
namespace Coupon.API.IntegrationEvents.Events;
|
||||||
|
|
||||||
|
public record OrderCouponRejectedIntegrationEvent : IntegrationEvent
|
||||||
|
{
|
||||||
|
public int OrderId { get; }
|
||||||
|
|
||||||
|
public string Code { get; }
|
||||||
|
|
||||||
|
public OrderCouponRejectedIntegrationEvent(int orderId, string code)
|
||||||
|
{
|
||||||
|
OrderId = orderId;
|
||||||
|
Code = code;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Coupon.API.IntegrationEvents.Events;
|
||||||
|
|
||||||
|
public record OrderStatusChangedToAwaitingCouponValidationIntegrationEvent : IntegrationEvent
|
||||||
|
{
|
||||||
|
[JsonProperty]
|
||||||
|
public int OrderId { get; private set; }
|
||||||
|
|
||||||
|
[JsonProperty]
|
||||||
|
public string OrderStatus { get; private set; }
|
||||||
|
|
||||||
|
[JsonProperty]
|
||||||
|
public string BuyerName { get; private set; }
|
||||||
|
|
||||||
|
[JsonProperty]
|
||||||
|
public string Code { get; private set; }
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Coupon.API.IntegrationEvents.Events;
|
||||||
|
|
||||||
|
public record OrderStatusChangedToCancelledIntegrationEvent : IntegrationEvent
|
||||||
|
{
|
||||||
|
[JsonProperty]
|
||||||
|
public int OrderId { get; private set; }
|
||||||
|
|
||||||
|
[JsonProperty]
|
||||||
|
public string OrderStatus { get; private set; }
|
||||||
|
|
||||||
|
[JsonProperty]
|
||||||
|
public string BuyerName { get; private set; }
|
||||||
|
|
||||||
|
[JsonProperty]
|
||||||
|
public string DiscountCode { get; private set; }
|
||||||
|
}
|
53
src/Services/Coupon/Coupon.API/Program.cs
Normal file
53
src/Services/Coupon/Coupon.API/Program.cs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
using System.IO;
|
||||||
|
using Autofac.Extensions.DependencyInjection;
|
||||||
|
using Coupon.API.Extensions;
|
||||||
|
using Coupon.API.Infrastructure;
|
||||||
|
using Coupon.API.Infrastructure.Repositories;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Serilog;
|
||||||
|
using Serilog.Events;
|
||||||
|
|
||||||
|
namespace Coupon.API
|
||||||
|
{
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
public static void Main(string[] args) =>
|
||||||
|
CreateHostBuilder(args)
|
||||||
|
.Build()
|
||||||
|
.SeedDatabaseStrategy<CouponContext>(context => new CouponSeed().SeedAsync(context).Wait())
|
||||||
|
.SubscribersIntegrationEvents()
|
||||||
|
.Run();
|
||||||
|
|
||||||
|
public static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||||
|
Host.CreateDefaultBuilder(args)
|
||||||
|
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
|
||||||
|
.ConfigureAppConfiguration((host, builder) =>
|
||||||
|
{
|
||||||
|
builder.SetBasePath(Directory.GetCurrentDirectory())
|
||||||
|
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
|
||||||
|
.AddJsonFile($"appsettings.{host.HostingEnvironment.EnvironmentName}.json", optional: false, reloadOnChange: true)
|
||||||
|
.AddEnvironmentVariables();
|
||||||
|
|
||||||
|
var config = builder.Build();
|
||||||
|
|
||||||
|
if (config.GetValue("UseVault", false))
|
||||||
|
{
|
||||||
|
builder.AddAzureKeyVault($"https://{config["Vault:Name"]}.vault.azure.net/", config["Vault:ClientId"], config["Vault:ClientSecret"]);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup<Startup>())
|
||||||
|
.UseSerilog((host, builder) =>
|
||||||
|
{
|
||||||
|
builder.MinimumLevel.Verbose()
|
||||||
|
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
|
||||||
|
.Enrich.WithProperty("ApplicationContext", host.HostingEnvironment.ApplicationName)
|
||||||
|
.Enrich.FromLogContext()
|
||||||
|
.WriteTo.Console()
|
||||||
|
.WriteTo.Seq(string.IsNullOrWhiteSpace(host.Configuration["Serilog:SeqServerUrl"]) ? "http://seq" : host.Configuration["Serilog:SeqServerUrl"])
|
||||||
|
.WriteTo.Http(string.IsNullOrWhiteSpace(host.Configuration["Serilog:LogstashUrl"]) ? "http://logstash:8080" : host.Configuration["Serilog:LogstashUrl"])
|
||||||
|
.ReadFrom.Configuration(host.Configuration);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"profiles": {
|
||||||
|
"Coupon.API": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
},
|
||||||
|
"applicationUrl": "https://localhost:49935;http://localhost:49936"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
94
src/Services/Coupon/Coupon.API/Startup.cs
Normal file
94
src/Services/Coupon/Coupon.API/Startup.cs
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
using Coupon.API.Extensions;
|
||||||
|
using Coupon.API.Filters;
|
||||||
|
using Coupon.API.IntegrationEvents.EventHandlers;
|
||||||
|
using Coupon.API.IntegrationEvents.Events;
|
||||||
|
using HealthChecks.UI.Client;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
namespace Coupon.API
|
||||||
|
{
|
||||||
|
public class Startup
|
||||||
|
{
|
||||||
|
public Startup(IConfiguration configuration)
|
||||||
|
{
|
||||||
|
Configuration = configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IConfiguration Configuration { get; }
|
||||||
|
|
||||||
|
public void ConfigureServices(IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddControllers(options => options.Filters.Add<ValidateModelAttribute>());
|
||||||
|
|
||||||
|
services.AddCustomSettings(Configuration)
|
||||||
|
.AddCouponRegister(Configuration)
|
||||||
|
.AddCustomPolicies()
|
||||||
|
.AddAppInsights(Configuration)
|
||||||
|
.AddEventBus(Configuration)
|
||||||
|
.AddCustomAuthentication(Configuration)
|
||||||
|
.AddCustomAuthorization()
|
||||||
|
.AddSwagger(Configuration)
|
||||||
|
.AddCustomHealthCheck(Configuration);
|
||||||
|
|
||||||
|
services.AddTransient<IIntegrationEventHandler<OrderStatusChangedToAwaitingCouponValidationIntegrationEvent>, OrderStatusChangedToAwaitingCouponValidationIntegrationEventHandler>();
|
||||||
|
services.AddTransient<IIntegrationEventHandler<OrderStatusChangedToCancelledIntegrationEvent>, OrderStatusChangedToCancelledIntegrationEventHandler>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||||
|
{
|
||||||
|
if (env.IsDevelopment())
|
||||||
|
{
|
||||||
|
app.UseDeveloperExceptionPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
var pathBase = Configuration["PATH_BASE"];
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(pathBase))
|
||||||
|
{
|
||||||
|
app.UsePathBase(pathBase);
|
||||||
|
}
|
||||||
|
|
||||||
|
app.UseSwagger()
|
||||||
|
.UseSwaggerUI(options =>
|
||||||
|
{
|
||||||
|
options.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Coupon.API V1");
|
||||||
|
options.OAuthClientId("couponswaggerui");
|
||||||
|
options.OAuthAppName("eShop-Learn.Coupon.API Swagger UI");
|
||||||
|
})
|
||||||
|
.UseCors("CorsPolicy")
|
||||||
|
.UseRouting()
|
||||||
|
.UseAuthentication()
|
||||||
|
.UseAuthorization()
|
||||||
|
.UseEndpoints(endpoints =>
|
||||||
|
{
|
||||||
|
endpoints.MapControllers();
|
||||||
|
endpoints.MapHealthChecks("/hc", new HealthCheckOptions
|
||||||
|
{
|
||||||
|
Predicate = _ => true,
|
||||||
|
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
|
||||||
|
});
|
||||||
|
endpoints.MapHealthChecks("/liveness", new HealthCheckOptions
|
||||||
|
{
|
||||||
|
Predicate = r => r.Name.Contains("self")
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
ConfigureEventBus(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ConfigureEventBus(IApplicationBuilder app)
|
||||||
|
{
|
||||||
|
var eventBus = app.ApplicationServices.GetRequiredService<IEventBus>();
|
||||||
|
|
||||||
|
eventBus.Subscribe<OrderStatusChangedToAwaitingCouponValidationIntegrationEvent, IIntegrationEventHandler<OrderStatusChangedToAwaitingCouponValidationIntegrationEvent>>();
|
||||||
|
eventBus.Subscribe<OrderStatusChangedToCancelledIntegrationEvent, IIntegrationEventHandler<OrderStatusChangedToCancelledIntegrationEvent>>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
18
src/Services/Coupon/Coupon.API/appsettings.Development.json
Normal file
18
src/Services/Coupon/Coupon.API/appsettings.Development.json
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"ConnectionString": "mongodb://localhost:27017",
|
||||||
|
"CouponMongoDatabase": "CouponDb",
|
||||||
|
"Serilog": {
|
||||||
|
"MinimumLevel": {
|
||||||
|
"Default": "Debug",
|
||||||
|
"Override": {
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.eShopOnContainers": "Debug",
|
||||||
|
"System": "Warning"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"IdentityUrlExternal": "http://localhost:5105",
|
||||||
|
"IdentityUrl": "http://localhost:5105",
|
||||||
|
"AzureServiceBusEnabled": false,
|
||||||
|
"EventBusConnection": "localhost"
|
||||||
|
}
|
28
src/Services/Coupon/Coupon.API/appsettings.json
Normal file
28
src/Services/Coupon/Coupon.API/appsettings.json
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"ConnectionString": null,
|
||||||
|
"CouponMongoDatabase": "CouponDb",
|
||||||
|
"UseCustomizationData": false,
|
||||||
|
"Serilog": {
|
||||||
|
"SeqServerUrl": null,
|
||||||
|
"LogstashUrl": null,
|
||||||
|
"MinimumLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Override": {
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.eShopOnContainers": "Information",
|
||||||
|
"System": "Warning"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"SubscriptionClientName": "Coupon",
|
||||||
|
"ApplicationInsights": {
|
||||||
|
"InstrumentationKey": ""
|
||||||
|
},
|
||||||
|
"EventBusRetryCount": 5,
|
||||||
|
"UseVault": false,
|
||||||
|
"Vault": {
|
||||||
|
"Name": "eshop",
|
||||||
|
"ClientId": "your-client-id",
|
||||||
|
"ClientSecret": "your-client-secret"
|
||||||
|
}
|
||||||
|
}
|
@ -24,6 +24,7 @@ COPY "Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj" "Services/Basket
|
|||||||
COPY "Services/Catalog/Catalog.API/Catalog.API.csproj" "Services/Catalog/Catalog.API/Catalog.API.csproj"
|
COPY "Services/Catalog/Catalog.API/Catalog.API.csproj" "Services/Catalog/Catalog.API/Catalog.API.csproj"
|
||||||
COPY "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj" "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj"
|
COPY "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj" "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj"
|
||||||
COPY "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj" "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj"
|
COPY "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj" "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj"
|
||||||
|
COPY "Services/Coupon/Coupon.API/Coupon.API.csproj" "Services/Coupon/Coupon.API/Coupon.API.csproj"
|
||||||
COPY "Services/Identity/Identity.API/Identity.API.csproj" "Services/Identity/Identity.API/Identity.API.csproj"
|
COPY "Services/Identity/Identity.API/Identity.API.csproj" "Services/Identity/Identity.API/Identity.API.csproj"
|
||||||
COPY "Services/Ordering/Ordering.API/Ordering.API.csproj" "Services/Ordering/Ordering.API/Ordering.API.csproj"
|
COPY "Services/Ordering/Ordering.API/Ordering.API.csproj" "Services/Ordering/Ordering.API/Ordering.API.csproj"
|
||||||
COPY "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj" "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj"
|
COPY "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj" "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj"
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
"windowsAuthentication": false,
|
"windowsAuthentication": false,
|
||||||
"anonymousAuthentication": true,
|
"anonymousAuthentication": true,
|
||||||
"iisExpress": {
|
"iisExpress": {
|
||||||
"applicationUrl": "http://localhost:54010/",
|
"applicationUrl": "http://localhost:49318/",
|
||||||
"sslPort": 0
|
"sslPort": 44350
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"profiles": {
|
"profiles": {
|
||||||
|
@ -24,6 +24,7 @@ COPY "Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj" "Services/Basket
|
|||||||
COPY "Services/Catalog/Catalog.API/Catalog.API.csproj" "Services/Catalog/Catalog.API/Catalog.API.csproj"
|
COPY "Services/Catalog/Catalog.API/Catalog.API.csproj" "Services/Catalog/Catalog.API/Catalog.API.csproj"
|
||||||
COPY "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj" "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj"
|
COPY "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj" "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj"
|
||||||
COPY "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj" "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj"
|
COPY "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj" "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj"
|
||||||
|
COPY "Services/Coupon/Coupon.API/Coupon.API.csproj" "Services/Coupon/Coupon.API/Coupon.API.csproj"
|
||||||
COPY "Services/Identity/Identity.API/Identity.API.csproj" "Services/Identity/Identity.API/Identity.API.csproj"
|
COPY "Services/Identity/Identity.API/Identity.API.csproj" "Services/Identity/Identity.API/Identity.API.csproj"
|
||||||
COPY "Services/Ordering/Ordering.API/Ordering.API.csproj" "Services/Ordering/Ordering.API/Ordering.API.csproj"
|
COPY "Services/Ordering/Ordering.API/Ordering.API.csproj" "Services/Ordering/Ordering.API/Ordering.API.csproj"
|
||||||
COPY "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj" "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj"
|
COPY "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj" "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj"
|
||||||
|
@ -24,6 +24,7 @@ COPY "Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj" "Services/Basket
|
|||||||
COPY "Services/Catalog/Catalog.API/Catalog.API.csproj" "Services/Catalog/Catalog.API/Catalog.API.csproj"
|
COPY "Services/Catalog/Catalog.API/Catalog.API.csproj" "Services/Catalog/Catalog.API/Catalog.API.csproj"
|
||||||
COPY "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj" "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj"
|
COPY "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj" "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj"
|
||||||
COPY "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj" "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj"
|
COPY "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj" "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj"
|
||||||
|
COPY "Services/Coupon/Coupon.API/Coupon.API.csproj" "Services/Coupon/Coupon.API/Coupon.API.csproj"
|
||||||
COPY "Services/Identity/Identity.API/Identity.API.csproj" "Services/Identity/Identity.API/Identity.API.csproj"
|
COPY "Services/Identity/Identity.API/Identity.API.csproj" "Services/Identity/Identity.API/Identity.API.csproj"
|
||||||
COPY "Services/Ordering/Ordering.API/Ordering.API.csproj" "Services/Ordering/Ordering.API/Ordering.API.csproj"
|
COPY "Services/Ordering/Ordering.API/Ordering.API.csproj" "Services/Ordering/Ordering.API/Ordering.API.csproj"
|
||||||
COPY "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj" "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj"
|
COPY "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj" "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj"
|
||||||
|
@ -24,6 +24,7 @@ COPY "Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj" "Services/Basket
|
|||||||
COPY "Services/Catalog/Catalog.API/Catalog.API.csproj" "Services/Catalog/Catalog.API/Catalog.API.csproj"
|
COPY "Services/Catalog/Catalog.API/Catalog.API.csproj" "Services/Catalog/Catalog.API/Catalog.API.csproj"
|
||||||
COPY "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj" "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj"
|
COPY "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj" "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj"
|
||||||
COPY "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj" "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj"
|
COPY "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj" "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj"
|
||||||
|
COPY "Services/Coupon/Coupon.API/Coupon.API.csproj" "Services/Coupon/Coupon.API/Coupon.API.csproj"
|
||||||
COPY "Services/Identity/Identity.API/Identity.API.csproj" "Services/Identity/Identity.API/Identity.API.csproj"
|
COPY "Services/Identity/Identity.API/Identity.API.csproj" "Services/Identity/Identity.API/Identity.API.csproj"
|
||||||
COPY "Services/Ordering/Ordering.API/Ordering.API.csproj" "Services/Ordering/Ordering.API/Ordering.API.csproj"
|
COPY "Services/Ordering/Ordering.API/Ordering.API.csproj" "Services/Ordering/Ordering.API/Ordering.API.csproj"
|
||||||
COPY "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj" "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj"
|
COPY "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj" "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj"
|
||||||
|
@ -24,6 +24,7 @@ COPY "Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj" "Services/Basket
|
|||||||
COPY "Services/Catalog/Catalog.API/Catalog.API.csproj" "Services/Catalog/Catalog.API/Catalog.API.csproj"
|
COPY "Services/Catalog/Catalog.API/Catalog.API.csproj" "Services/Catalog/Catalog.API/Catalog.API.csproj"
|
||||||
COPY "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj" "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj"
|
COPY "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj" "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj"
|
||||||
COPY "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj" "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj"
|
COPY "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj" "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj"
|
||||||
|
COPY "Services/Coupon/Coupon.API/Coupon.API.csproj" "Services/Coupon/Coupon.API/Coupon.API.csproj"
|
||||||
COPY "Services/Identity/Identity.API/Identity.API.csproj" "Services/Identity/Identity.API/Identity.API.csproj"
|
COPY "Services/Identity/Identity.API/Identity.API.csproj" "Services/Identity/Identity.API/Identity.API.csproj"
|
||||||
COPY "Services/Ordering/Ordering.API/Ordering.API.csproj" "Services/Ordering/Ordering.API/Ordering.API.csproj"
|
COPY "Services/Ordering/Ordering.API/Ordering.API.csproj" "Services/Ordering/Ordering.API/Ordering.API.csproj"
|
||||||
COPY "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj" "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj"
|
COPY "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj" "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj"
|
||||||
|
@ -24,6 +24,7 @@ COPY "Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj" "Services/Basket
|
|||||||
COPY "Services/Catalog/Catalog.API/Catalog.API.csproj" "Services/Catalog/Catalog.API/Catalog.API.csproj"
|
COPY "Services/Catalog/Catalog.API/Catalog.API.csproj" "Services/Catalog/Catalog.API/Catalog.API.csproj"
|
||||||
COPY "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj" "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj"
|
COPY "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj" "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj"
|
||||||
COPY "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj" "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj"
|
COPY "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj" "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj"
|
||||||
|
COPY "Services/Coupon/Coupon.API/Coupon.API.csproj" "Services/Coupon/Coupon.API/Coupon.API.csproj"
|
||||||
COPY "Services/Identity/Identity.API/Identity.API.csproj" "Services/Identity/Identity.API/Identity.API.csproj"
|
COPY "Services/Identity/Identity.API/Identity.API.csproj" "Services/Identity/Identity.API/Identity.API.csproj"
|
||||||
COPY "Services/Ordering/Ordering.API/Ordering.API.csproj" "Services/Ordering/Ordering.API/Ordering.API.csproj"
|
COPY "Services/Ordering/Ordering.API/Ordering.API.csproj" "Services/Ordering/Ordering.API/Ordering.API.csproj"
|
||||||
COPY "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj" "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj"
|
COPY "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj" "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj"
|
||||||
|
@ -24,6 +24,7 @@ COPY "Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj" "Services/Basket
|
|||||||
COPY "Services/Catalog/Catalog.API/Catalog.API.csproj" "Services/Catalog/Catalog.API/Catalog.API.csproj"
|
COPY "Services/Catalog/Catalog.API/Catalog.API.csproj" "Services/Catalog/Catalog.API/Catalog.API.csproj"
|
||||||
COPY "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj" "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj"
|
COPY "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj" "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj"
|
||||||
COPY "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj" "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj"
|
COPY "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj" "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj"
|
||||||
|
COPY "Services/Coupon/Coupon.API/Coupon.API.csproj" "Services/Coupon/Coupon.API/Coupon.API.csproj"
|
||||||
COPY "Services/Identity/Identity.API/Identity.API.csproj" "Services/Identity/Identity.API/Identity.API.csproj"
|
COPY "Services/Identity/Identity.API/Identity.API.csproj" "Services/Identity/Identity.API/Identity.API.csproj"
|
||||||
COPY "Services/Ordering/Ordering.API/Ordering.API.csproj" "Services/Ordering/Ordering.API/Ordering.API.csproj"
|
COPY "Services/Ordering/Ordering.API/Ordering.API.csproj" "Services/Ordering/Ordering.API/Ordering.API.csproj"
|
||||||
COPY "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj" "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj"
|
COPY "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj" "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj"
|
||||||
|
@ -13,6 +13,7 @@ import { StorageService } from '../shared/services/storage.service';
|
|||||||
|
|
||||||
import { Observable, Observer, Subject } from 'rxjs';
|
import { Observable, Observer, Subject } from 'rxjs';
|
||||||
import { map, catchError, tap } from 'rxjs/operators';
|
import { map, catchError, tap } from 'rxjs/operators';
|
||||||
|
import { ICoupon } from '../shared/models/coupon.model';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class BasketService {
|
export class BasketService {
|
||||||
@ -95,6 +96,27 @@ export class BasketService {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkValidationCoupon(code: string): Observable<ICoupon> {
|
||||||
|
let url = this.purchaseUrl + `/cp/api/v1/coupon/${code}`;
|
||||||
|
|
||||||
|
return this.service
|
||||||
|
.get(url)
|
||||||
|
.pipe<ICoupon>(map<Response, ICoupon>((response) =>
|
||||||
|
{
|
||||||
|
console.log(`Coupon: ${response.json()} (${response.ok})`);
|
||||||
|
var item = <ICoupon>response.json[0];
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
item.message = "Valid coupon";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
item.message = "The coupon is not valid or has already been used";
|
||||||
|
}
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
mapBasketInfoCheckout(order: IOrder): IBasketCheckout {
|
mapBasketInfoCheckout(order: IOrder): IBasketCheckout {
|
||||||
let basketCheckout = <IBasketCheckout>{};
|
let basketCheckout = <IBasketCheckout>{};
|
||||||
|
|
||||||
|
@ -34,6 +34,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
|
<div class="d-flex align-items-center justify-content-end mt-4 mb-4 text-uppercase">
|
||||||
|
<div>Subtotal</div>
|
||||||
|
<div class="ml-3">${{order.subtotal | number:'.2-2'}}</div>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex align-items-center justify-content-end mt-4 mb-4 text-uppercase">
|
||||||
|
<div>{{order.coupon}}</div>
|
||||||
|
<div class="ml-3">- ${{order.discount | number:'.2-2'}}</div>
|
||||||
|
</div>-->
|
||||||
|
|
||||||
<div class="d-flex align-items-center justify-content-end mt-4 mb-4 text-uppercase u-text-xl">
|
<div class="d-flex align-items-center justify-content-end mt-4 mb-4 text-uppercase u-text-xl">
|
||||||
<div>Total</div>
|
<div>Total</div>
|
||||||
<div class="ml-3">${{order.total | number:'.2-2'}}</div>
|
<div class="ml-3">${{order.total | number:'.2-2'}}</div>
|
||||||
|
@ -84,6 +84,38 @@
|
|||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
|
<div class="d-flex align-items-center justify-content-end mt-4 mb-4 text-uppercase">
|
||||||
|
<div>Subtotal</div>
|
||||||
|
<div class="ml-3">${{order.total | number:'.2-2'}}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-flex flex-nowrap justify-content-between align-items-center mb-3 mt-3">
|
||||||
|
<div>
|
||||||
|
<div *ngIf="!coupon">
|
||||||
|
<div class="u-text-uppercase">Have a discount code?</div>
|
||||||
|
<div class="d-flex flex-nowrap justify-content-between align-items-center mt-1">
|
||||||
|
<input #discountcode
|
||||||
|
class="esh-orders_new-coupon mr-2 form-control"
|
||||||
|
type="text"
|
||||||
|
placeholder="Coupon number"
|
||||||
|
(keydown)="keyDownValidationCoupon($event, discountcode.value)">
|
||||||
|
<button type="button"
|
||||||
|
(click)="checkValidationCoupon(discountcode.value)"
|
||||||
|
class="btn btn-secondary u-minwidth-unset">
|
||||||
|
Apply
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="mt-1" *ngIf="couponValidationMessage">{{couponValidationMessage}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex align-items-center justify-content-end text-uppercase">
|
||||||
|
<div *ngIf="coupon?.code">{{coupon?.code}}</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-right ml-3" *ngIf="coupon?.discount">-${{coupon?.discount | number:'.2-2'}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="divider d-flex align-items-center justify-content-end mb-4 pt-4 text-uppercase u-text-xl">
|
<div class="divider d-flex align-items-center justify-content-end mb-4 pt-4 text-uppercase u-text-xl">
|
||||||
<div>Total</div>
|
<div>Total</div>
|
||||||
<div class="ml-3">${{ order.total | number:'.2-2'}}</div>
|
<div class="ml-3">${{ order.total | number:'.2-2'}}</div>
|
||||||
|
@ -6,7 +6,7 @@ import { OrdersService } from '../orders.service';
|
|||||||
import { BasketService } from '../../basket/basket.service';
|
import { BasketService } from '../../basket/basket.service';
|
||||||
import { IOrder } from '../../shared/models/order.model';
|
import { IOrder } from '../../shared/models/order.model';
|
||||||
import { BasketWrapperService } from '../../shared/services/basket.wrapper.service';
|
import { BasketWrapperService } from '../../shared/services/basket.wrapper.service';
|
||||||
|
import { ICoupon } from '../../shared/models/coupon.model';
|
||||||
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
@ -19,7 +19,9 @@ export class OrdersNewComponent implements OnInit {
|
|||||||
newOrderForm: FormGroup; // new order form
|
newOrderForm: FormGroup; // new order form
|
||||||
isOrderProcessing: boolean;
|
isOrderProcessing: boolean;
|
||||||
errorReceived: boolean;
|
errorReceived: boolean;
|
||||||
|
coupon: ICoupon;
|
||||||
order: IOrder;
|
order: IOrder;
|
||||||
|
couponValidationMessage: string;
|
||||||
|
|
||||||
constructor(private orderService: OrdersService, private basketService: BasketService, fb: FormBuilder, private router: Router) {
|
constructor(private orderService: OrdersService, private basketService: BasketService, fb: FormBuilder, private router: Router) {
|
||||||
// Obtain user profile information
|
// Obtain user profile information
|
||||||
@ -39,6 +41,23 @@ export class OrdersNewComponent implements OnInit {
|
|||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
keyDownValidationCoupon(event: KeyboardEvent, discountCode: string) {
|
||||||
|
if(event.keyCode === 13) {
|
||||||
|
event.preventDefault();
|
||||||
|
this.checkValidationCoupon(discountCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkValidationCoupon(discountCode: string) {
|
||||||
|
this.couponValidationMessage = null;
|
||||||
|
this.coupon = null;
|
||||||
|
this.orderService
|
||||||
|
.checkValidationCoupon(discountCode)
|
||||||
|
.subscribe(
|
||||||
|
coupon => this.coupon = coupon,
|
||||||
|
error => this.couponValidationMessage = 'The coupon is not valid or it\'s been redeemed already!' );
|
||||||
|
}
|
||||||
|
|
||||||
submitForm(value: any) {
|
submitForm(value: any) {
|
||||||
this.order.street = this.newOrderForm.controls['street'].value;
|
this.order.street = this.newOrderForm.controls['street'].value;
|
||||||
this.order.city = this.newOrderForm.controls['city'].value;
|
this.order.city = this.newOrderForm.controls['city'].value;
|
||||||
@ -49,6 +68,14 @@ export class OrdersNewComponent implements OnInit {
|
|||||||
this.order.cardholdername = this.newOrderForm.controls['cardholdername'].value;
|
this.order.cardholdername = this.newOrderForm.controls['cardholdername'].value;
|
||||||
this.order.cardexpiration = new Date(20 + this.newOrderForm.controls['expirationdate'].value.split('/')[1], this.newOrderForm.controls['expirationdate'].value.split('/')[0]);
|
this.order.cardexpiration = new Date(20 + this.newOrderForm.controls['expirationdate'].value.split('/')[1], this.newOrderForm.controls['expirationdate'].value.split('/')[0]);
|
||||||
this.order.cardsecuritynumber = this.newOrderForm.controls['securitycode'].value;
|
this.order.cardsecuritynumber = this.newOrderForm.controls['securitycode'].value;
|
||||||
|
|
||||||
|
if (this.coupon) {
|
||||||
|
console.log(`Coupon: ${this.coupon.code} (${this.coupon.discount})`);
|
||||||
|
|
||||||
|
this.order.coupon = this.coupon.code;
|
||||||
|
this.order.discount = this.coupon.discount;
|
||||||
|
}
|
||||||
|
|
||||||
let basketCheckout = this.basketService.mapBasketInfoCheckout(this.order);
|
let basketCheckout = this.basketService.mapBasketInfoCheckout(this.order);
|
||||||
this.basketService.setBasketCheckout(basketCheckout)
|
this.basketService.setBasketCheckout(basketCheckout)
|
||||||
.pipe(catchError((errMessage) => {
|
.pipe(catchError((errMessage) => {
|
||||||
|
@ -10,6 +10,7 @@ import { BasketWrapperService } from '../shared/services/basket.wrapper.service'
|
|||||||
|
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { tap, map } from 'rxjs/operators';
|
import { tap, map } from 'rxjs/operators';
|
||||||
|
import { ICoupon } from '../shared/models/coupon.model';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class OrdersService {
|
export class OrdersService {
|
||||||
@ -48,6 +49,14 @@ export class OrdersService {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkValidationCoupon(code: string): Observable<ICoupon> {
|
||||||
|
let url = this.ordersUrl + `/cp/api/v1/coupon/${code}`;
|
||||||
|
|
||||||
|
return this.service.get(url).pipe<ICoupon>(tap((response: any) => {
|
||||||
|
return response;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
mapOrderAndIdentityInfoNewOrder(): IOrder {
|
mapOrderAndIdentityInfoNewOrder(): IOrder {
|
||||||
let order = <IOrder>{};
|
let order = <IOrder>{};
|
||||||
let basket = this.basketService.basket;
|
let basket = this.basketService.basket;
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
export interface ICoupon {
|
||||||
|
discount: number;
|
||||||
|
code: string;
|
||||||
|
message: string
|
||||||
|
}
|
@ -10,6 +10,9 @@ export interface IOrderDetail {
|
|||||||
state: string;
|
state: string;
|
||||||
zipcode: string;
|
zipcode: string;
|
||||||
country: number;
|
country: number;
|
||||||
|
subtotal: number;
|
||||||
|
coupon: string;
|
||||||
|
discount: number;
|
||||||
total: number;
|
total: number;
|
||||||
orderitems: IOrderItem[];
|
orderitems: IOrderItem[];
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,9 @@ export interface IOrder {
|
|||||||
cardtypeid: number;
|
cardtypeid: number;
|
||||||
buyer: string;
|
buyer: string;
|
||||||
ordernumber: string;
|
ordernumber: string;
|
||||||
|
subtotal: number,
|
||||||
|
coupon: string;
|
||||||
|
discount: number;
|
||||||
total: number;
|
total: number;
|
||||||
orderItems: IOrderItem[];
|
orderItems: IOrderItem[];
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,7 @@ COPY "Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj" "Services/Basket
|
|||||||
COPY "Services/Catalog/Catalog.API/Catalog.API.csproj" "Services/Catalog/Catalog.API/Catalog.API.csproj"
|
COPY "Services/Catalog/Catalog.API/Catalog.API.csproj" "Services/Catalog/Catalog.API/Catalog.API.csproj"
|
||||||
COPY "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj" "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj"
|
COPY "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj" "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj"
|
||||||
COPY "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj" "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj"
|
COPY "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj" "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj"
|
||||||
|
COPY "Services/Coupon/Coupon.API/Coupon.API.csproj" "Services/Coupon/Coupon.API/Coupon.API.csproj"
|
||||||
COPY "Services/Identity/Identity.API/Identity.API.csproj" "Services/Identity/Identity.API/Identity.API.csproj"
|
COPY "Services/Identity/Identity.API/Identity.API.csproj" "Services/Identity/Identity.API/Identity.API.csproj"
|
||||||
COPY "Services/Ordering/Ordering.API/Ordering.API.csproj" "Services/Ordering/Ordering.API/Ordering.API.csproj"
|
COPY "Services/Ordering/Ordering.API/Ordering.API.csproj" "Services/Ordering/Ordering.API/Ordering.API.csproj"
|
||||||
COPY "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj" "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj"
|
COPY "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj" "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj"
|
||||||
|
@ -24,6 +24,7 @@ COPY "Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj" "Services/Basket
|
|||||||
COPY "Services/Catalog/Catalog.API/Catalog.API.csproj" "Services/Catalog/Catalog.API/Catalog.API.csproj"
|
COPY "Services/Catalog/Catalog.API/Catalog.API.csproj" "Services/Catalog/Catalog.API/Catalog.API.csproj"
|
||||||
COPY "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj" "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj"
|
COPY "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj" "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj"
|
||||||
COPY "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj" "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj"
|
COPY "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj" "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj"
|
||||||
|
COPY "Services/Coupon/Coupon.API/Coupon.API.csproj" "Services/Coupon/Coupon.API/Coupon.API.csproj"
|
||||||
COPY "Services/Identity/Identity.API/Identity.API.csproj" "Services/Identity/Identity.API/Identity.API.csproj"
|
COPY "Services/Identity/Identity.API/Identity.API.csproj" "Services/Identity/Identity.API/Identity.API.csproj"
|
||||||
COPY "Services/Ordering/Ordering.API/Ordering.API.csproj" "Services/Ordering/Ordering.API/Ordering.API.csproj"
|
COPY "Services/Ordering/Ordering.API/Ordering.API.csproj" "Services/Ordering/Ordering.API/Ordering.API.csproj"
|
||||||
COPY "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj" "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj"
|
COPY "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj" "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj"
|
||||||
|
@ -25,6 +25,7 @@ COPY "Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj" "Services/Basket
|
|||||||
COPY "Services/Catalog/Catalog.API/Catalog.API.csproj" "Services/Catalog/Catalog.API/Catalog.API.csproj"
|
COPY "Services/Catalog/Catalog.API/Catalog.API.csproj" "Services/Catalog/Catalog.API/Catalog.API.csproj"
|
||||||
COPY "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj" "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj"
|
COPY "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj" "Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj"
|
||||||
COPY "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj" "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj"
|
COPY "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj" "Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj"
|
||||||
|
COPY "Services/Coupon/Coupon.API/Coupon.API.csproj" "Services/Coupon/Coupon.API/Coupon.API.csproj"
|
||||||
COPY "Services/Identity/Identity.API/Identity.API.csproj" "Services/Identity/Identity.API/Identity.API.csproj"
|
COPY "Services/Identity/Identity.API/Identity.API.csproj" "Services/Identity/Identity.API/Identity.API.csproj"
|
||||||
COPY "Services/Ordering/Ordering.API/Ordering.API.csproj" "Services/Ordering/Ordering.API/Ordering.API.csproj"
|
COPY "Services/Ordering/Ordering.API/Ordering.API.csproj" "Services/Ordering/Ordering.API/Ordering.API.csproj"
|
||||||
COPY "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj" "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj"
|
COPY "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj" "Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj"
|
||||||
|
@ -44,6 +44,14 @@ services:
|
|||||||
- sqldata
|
- sqldata
|
||||||
- rabbitmq
|
- rabbitmq
|
||||||
|
|
||||||
|
coupon-api:
|
||||||
|
image: ${REGISTRY:-eshop}/coupon.api:${PLATFORM:-linux}-${TAG:-latest}
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Services/Coupon/Coupon.API/Dockerfile
|
||||||
|
depends_on:
|
||||||
|
- nosqldata
|
||||||
|
|
||||||
ordering-api:
|
ordering-api:
|
||||||
image: ${REGISTRY:-eshop}/ordering.api:${PLATFORM:-linux}-${TAG:-latest}
|
image: ${REGISTRY:-eshop}/ordering.api:${PLATFORM:-linux}-${TAG:-latest}
|
||||||
build:
|
build:
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio Version 16
|
# Visual Studio Version 17
|
||||||
VisualStudioVersion = 16.0.29020.237
|
VisualStudioVersion = 17.2.32929.388
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{FEA0C318-FFED-4D39-8781-265718CA43DD}"
|
Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{FEA0C318-FFED-4D39-8781-265718CA43DD}"
|
||||||
EndProject
|
EndProject
|
||||||
@ -124,6 +124,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{373D8AA1
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventBus.Tests", "BuildingBlocks\EventBus\EventBus.Tests\EventBus.Tests.csproj", "{95D735BE-2899-4495-BE3F-2600E93B4E3C}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventBus.Tests", "BuildingBlocks\EventBus\EventBus.Tests\EventBus.Tests.csproj", "{95D735BE-2899-4495-BE3F-2600E93B4E3C}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Coupon", "Coupon", "{71D3CD0A-5583-4F82-99D6-5035BF0EE2C0}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Coupon.API", "Services\Coupon\Coupon.API\Coupon.API.csproj", "{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
|
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
|
||||||
@ -1530,6 +1534,54 @@ Global
|
|||||||
{95D735BE-2899-4495-BE3F-2600E93B4E3C}.Release|x64.Build.0 = Release|Any CPU
|
{95D735BE-2899-4495-BE3F-2600E93B4E3C}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{95D735BE-2899-4495-BE3F-2600E93B4E3C}.Release|x86.ActiveCfg = Release|Any CPU
|
{95D735BE-2899-4495-BE3F-2600E93B4E3C}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{95D735BE-2899-4495-BE3F-2600E93B4E3C}.Release|x86.Build.0 = Release|Any CPU
|
{95D735BE-2899-4495-BE3F-2600E93B4E3C}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.AppStore|ARM.ActiveCfg = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.AppStore|ARM.Build.0 = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.AppStore|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.AppStore|x64.Build.0 = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.AppStore|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.AppStore|x86.Build.0 = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Release|ARM.Build.0 = Release|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Release|iPhone.Build.0 = Release|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083}.Release|x86.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@ -1588,6 +1640,8 @@ Global
|
|||||||
{B62E859F-825E-4C8B-93EC-5966EACFD026} = {798BFC44-2CCD-45FA-B37A-5173B03C2B30}
|
{B62E859F-825E-4C8B-93EC-5966EACFD026} = {798BFC44-2CCD-45FA-B37A-5173B03C2B30}
|
||||||
{373D8AA1-36BE-49EC-89F0-6CB736666285} = {807BB76E-B2BB-47A2-A57B-3D1B20FF5E7F}
|
{373D8AA1-36BE-49EC-89F0-6CB736666285} = {807BB76E-B2BB-47A2-A57B-3D1B20FF5E7F}
|
||||||
{95D735BE-2899-4495-BE3F-2600E93B4E3C} = {373D8AA1-36BE-49EC-89F0-6CB736666285}
|
{95D735BE-2899-4495-BE3F-2600E93B4E3C} = {373D8AA1-36BE-49EC-89F0-6CB736666285}
|
||||||
|
{71D3CD0A-5583-4F82-99D6-5035BF0EE2C0} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8}
|
||||||
|
{53D3EE9A-EA1E-46A7-9B62-1D19E6FE2083} = {71D3CD0A-5583-4F82-99D6-5035BF0EE2C0}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {25728519-5F0F-4973-8A64-0A81EB4EA8D9}
|
SolutionGuid = {25728519-5F0F-4973-8A64-0A81EB4EA8D9}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user