Compare commits
4 Commits
master
...
extensions
Author | SHA1 | Date | |
---|---|---|---|
34651e481e | |||
d11c00518b | |||
d8e55707a5 | |||
bc57c9d56a |
@ -2,15 +2,15 @@ version: 2
|
||||
jobs:
|
||||
fast_tests:
|
||||
machine:
|
||||
image: ubuntu-2004:2024.11.1
|
||||
enabled: true
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
command: |
|
||||
cd .circleci && ./run-tests.sh "Fast=Fast|ThirdParty=ThirdParty" && ./can-build.sh
|
||||
cd .circleci && ./run-tests.sh "Fast=Fast" && ./can-build.sh
|
||||
selenium_tests:
|
||||
machine:
|
||||
image: ubuntu-2004:2024.11.1
|
||||
enabled: true
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
@ -18,35 +18,101 @@ jobs:
|
||||
cd .circleci && ./run-tests.sh "Selenium=Selenium"
|
||||
integration_tests:
|
||||
machine:
|
||||
image: ubuntu-2004:2024.11.1
|
||||
enabled: true
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
command: |
|
||||
cd .circleci && ./run-tests.sh "Integration=Integration"
|
||||
trigger_docs_build:
|
||||
external_tests:
|
||||
machine:
|
||||
image: ubuntu-2004:2024.11.1
|
||||
enabled: true
|
||||
steps:
|
||||
- run:
|
||||
command: |
|
||||
curl -X POST -H "Authorization: token $GH_PAT" -H "Accept: application/vnd.github.everest-preview+json" -H "Content-Type: application/json" https://api.github.com/repos/btcpayserver/btcpayserver-doc/dispatches --data '{"event_type": "build_docs"}'
|
||||
# publish jobs require $DOCKERHUB_REPO, $DOCKERHUB_USER, $DOCKERHUB_PASS defined
|
||||
docker:
|
||||
docker:
|
||||
- image: cimg/base:stable
|
||||
steps:
|
||||
- setup_remote_docker
|
||||
- checkout
|
||||
- run:
|
||||
command: |
|
||||
if [ "$CIRCLE_PROJECT_USERNAME" == "btcpayserver" ] && [ "$CIRCLE_PROJECT_REPONAME" == "btcpayserver" ]; then
|
||||
cd .circleci && ./run-tests.sh "ExternalIntegration=ExternalIntegration"
|
||||
else
|
||||
echo "Skipping running ExternalIntegration tests outside of context of main user and repository that have access to secrets"
|
||||
fi
|
||||
|
||||
|
||||
# publish jobs require $DOCKERHUB_REPO, $DOCKERHUB_USER, $DOCKERHUB_PASS defined
|
||||
amd64:
|
||||
machine:
|
||||
enabled: true
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
command: |
|
||||
LATEST_TAG=${CIRCLE_TAG:1} #trim v from tag
|
||||
GIT_COMMIT=$(git rev-parse HEAD)
|
||||
#
|
||||
docker login --username=$DOCKERHUB_USER --password=$DOCKERHUB_PASS
|
||||
docker buildx create --use
|
||||
DOCKER_BUILDX_OPTS="--platform linux/amd64,linux/arm64,linux/arm/v7 --build-arg GIT_COMMIT=${GIT_COMMIT} --push"
|
||||
docker buildx build $DOCKER_BUILDX_OPTS -t $DOCKERHUB_REPO:$LATEST_TAG .
|
||||
sudo docker build --pull -t $DOCKERHUB_REPO:$LATEST_TAG-amd64 -f amd64.Dockerfile .
|
||||
sudo docker build --pull --build-arg CONFIGURATION_NAME=Altcoins-Release -t $DOCKERHUB_REPO:$LATEST_TAG-altcoins-amd64 -f amd64.Dockerfile .
|
||||
sudo docker login --username=$DOCKERHUB_USER --password=$DOCKERHUB_PASS
|
||||
sudo docker push $DOCKERHUB_REPO:$LATEST_TAG-amd64
|
||||
sudo docker push $DOCKERHUB_REPO:$LATEST_TAG-altcoins-amd64
|
||||
|
||||
arm32v7:
|
||||
machine:
|
||||
enabled: true
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
command: |
|
||||
sudo docker run --rm --privileged multiarch/qemu-user-static:register --reset
|
||||
LATEST_TAG=${CIRCLE_TAG:1} #trim v from tag
|
||||
#
|
||||
sudo docker build --pull -t $DOCKERHUB_REPO:$LATEST_TAG-arm32v7 -f arm32v7.Dockerfile .
|
||||
sudo docker build --pull --build-arg CONFIGURATION_NAME=Altcoins-Release -t $DOCKERHUB_REPO:$LATEST_TAG-altcoins-arm32v7 -f arm32v7.Dockerfile .
|
||||
sudo docker login --username=$DOCKERHUB_USER --password=$DOCKERHUB_PASS
|
||||
sudo docker push $DOCKERHUB_REPO:$LATEST_TAG-arm32v7
|
||||
sudo docker push $DOCKERHUB_REPO:$LATEST_TAG-altcoins-arm32v7
|
||||
|
||||
arm64v8:
|
||||
machine:
|
||||
enabled: true
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
command: |
|
||||
sudo docker run --rm --privileged multiarch/qemu-user-static:register --reset
|
||||
LATEST_TAG=${CIRCLE_TAG:1} #trim v from tag
|
||||
#
|
||||
sudo docker build --pull -t $DOCKERHUB_REPO:$LATEST_TAG-arm64v8 -f arm64v8.Dockerfile .
|
||||
sudo docker build --build-arg CONFIGURATION_NAME=Altcoins-Release --pull -t $DOCKERHUB_REPO:$LATEST_TAG-altcoins-arm64v8 -f arm64v8.Dockerfile .
|
||||
sudo docker login --username=$DOCKERHUB_USER --password=$DOCKERHUB_PASS
|
||||
sudo docker push $DOCKERHUB_REPO:$LATEST_TAG-arm64v8
|
||||
sudo docker push $DOCKERHUB_REPO:$LATEST_TAG-altcoins-arm64v8
|
||||
|
||||
multiarch:
|
||||
machine:
|
||||
enabled: true
|
||||
image: circleci/classic:201808-01
|
||||
steps:
|
||||
- run:
|
||||
command: |
|
||||
# Turn on Experimental features
|
||||
sudo mkdir $HOME/.docker
|
||||
sudo sh -c 'echo "{ \"experimental\": \"enabled\" }" >> $HOME/.docker/config.json'
|
||||
#
|
||||
sudo docker login --username=$DOCKERHUB_USER --password=$DOCKERHUB_PASS
|
||||
#
|
||||
LATEST_TAG=${CIRCLE_TAG:1} #trim v from tag
|
||||
sudo docker manifest create --amend $DOCKERHUB_REPO:$LATEST_TAG $DOCKERHUB_REPO:$LATEST_TAG-amd64 $DOCKERHUB_REPO:$LATEST_TAG-arm32v7 $DOCKERHUB_REPO:$LATEST_TAG-arm64v8
|
||||
sudo docker manifest annotate $DOCKERHUB_REPO:$LATEST_TAG $DOCKERHUB_REPO:$LATEST_TAG-amd64 --os linux --arch amd64
|
||||
sudo docker manifest annotate $DOCKERHUB_REPO:$LATEST_TAG $DOCKERHUB_REPO:$LATEST_TAG-arm32v7 --os linux --arch arm --variant v7
|
||||
sudo docker manifest annotate $DOCKERHUB_REPO:$LATEST_TAG $DOCKERHUB_REPO:$LATEST_TAG-arm64v8 --os linux --arch arm64 --variant v8
|
||||
sudo docker manifest push $DOCKERHUB_REPO:$LATEST_TAG -p
|
||||
|
||||
|
||||
sudo docker manifest create --amend $DOCKERHUB_REPO:$LATEST_TAG-altcoins $DOCKERHUB_REPO:$LATEST_TAG-altcoins-amd64 $DOCKERHUB_REPO:$LATEST_TAG-altcoins-arm32v7 $DOCKERHUB_REPO:$LATEST_TAG-altcoins-arm64v8
|
||||
sudo docker manifest annotate $DOCKERHUB_REPO:$LATEST_TAG-altcoins $DOCKERHUB_REPO:$LATEST_TAG-altcoins-amd64 --os linux --arch amd64
|
||||
sudo docker manifest annotate $DOCKERHUB_REPO:$LATEST_TAG-altcoins $DOCKERHUB_REPO:$LATEST_TAG-altcoins-arm32v7 --os linux --arch arm --variant v7
|
||||
sudo docker manifest annotate $DOCKERHUB_REPO:$LATEST_TAG-altcoins $DOCKERHUB_REPO:$LATEST_TAG-altcoins-arm64v8 --os linux --arch arm64 --variant v8
|
||||
sudo docker manifest push $DOCKERHUB_REPO:$LATEST_TAG-altcoins -p
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
build_and_test:
|
||||
@ -54,16 +120,13 @@ workflows:
|
||||
- fast_tests
|
||||
- selenium_tests
|
||||
- integration_tests
|
||||
publish:
|
||||
jobs:
|
||||
- trigger_docs_build:
|
||||
- external_tests:
|
||||
filters:
|
||||
branches:
|
||||
ignore: /.*/
|
||||
# only act on version tags
|
||||
tags:
|
||||
only: /(v[1-9]+(\.[0-9]+)*(-[a-z0-9-]+)?)|(v[a-z0-9-]+)/
|
||||
- docker:
|
||||
only: master
|
||||
publish:
|
||||
jobs:
|
||||
- amd64:
|
||||
filters:
|
||||
# ignore any commit on any branch by default
|
||||
branches:
|
||||
@ -71,5 +134,28 @@ workflows:
|
||||
# only act on version tags v1.0.0.88 or v1.0.2-1
|
||||
# OR feature tags like vlndseedbackup
|
||||
# OR features on specific versions like v1.0.0.88-lndseedbackup-1
|
||||
tags:
|
||||
|
||||
only: /(v[1-9]+(\.[0-9]+)*(-[a-z0-9-]+)?)|(v[a-z0-9-]+)/
|
||||
- arm32v7:
|
||||
filters:
|
||||
branches:
|
||||
ignore: /.*/
|
||||
tags:
|
||||
only: /(v[1-9]+(\.[0-9]+)*(-[a-z0-9-]+)?)|(v[a-z0-9-]+)/
|
||||
- arm64v8:
|
||||
filters:
|
||||
branches:
|
||||
ignore: /.*/
|
||||
tags:
|
||||
only: /(v[1-9]+(\.[0-9]+)*(-[a-z0-9-]+)?)|(v[a-z0-9-]+)/
|
||||
- multiarch:
|
||||
requires:
|
||||
- amd64
|
||||
- arm32v7
|
||||
- arm64v8
|
||||
filters:
|
||||
branches:
|
||||
ignore: /.*/
|
||||
tags:
|
||||
only: /(v[1-9]+(\.[0-9]+)*(-[a-z0-9-]+)?)|(v[a-z0-9-]+)/
|
||||
|
@ -2,17 +2,8 @@
|
||||
set -e
|
||||
|
||||
cd ../BTCPayServer.Tests
|
||||
docker-compose --version
|
||||
docker-compose -f "docker-compose.altcoins.yml" down -v
|
||||
|
||||
# For some reason, docker-compose pull fails time to time, so we try several times
|
||||
n=0
|
||||
until [ "$n" -ge 10 ]
|
||||
do
|
||||
docker-compose -f "docker-compose.altcoins.yml" pull && break
|
||||
n=$((n+1))
|
||||
sleep 5
|
||||
done
|
||||
|
||||
docker-compose -v
|
||||
docker-compose -f "docker-compose.altcoins.yml" down --v
|
||||
docker-compose -f "docker-compose.altcoins.yml" pull
|
||||
docker-compose -f "docker-compose.altcoins.yml" build
|
||||
docker-compose -f "docker-compose.altcoins.yml" run -e "TEST_FILTERS=$1" tests
|
||||
|
@ -11,14 +11,10 @@ insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
charset = utf-8
|
||||
space_before_self_closing = true
|
||||
|
||||
[*.json]
|
||||
[launchSettings.json]
|
||||
indent_size = 2
|
||||
|
||||
[swagger*.json]
|
||||
indent_size = 4
|
||||
|
||||
# C# files
|
||||
[*.cs]
|
||||
# New line preferences
|
||||
@ -71,7 +67,7 @@ dotnet_naming_symbols.private_internal_fields.applicable_kinds = field
|
||||
dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal
|
||||
|
||||
dotnet_naming_style.camel_case_underscore_style.required_prefix = _
|
||||
dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case
|
||||
dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case
|
||||
|
||||
# Code style defaults
|
||||
dotnet_sort_system_directives_first = true
|
||||
@ -125,11 +121,8 @@ csharp_space_between_method_declaration_name_and_open_parenthesis = false
|
||||
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
||||
csharp_space_between_parentheses = false
|
||||
csharp_space_between_square_brackets = false
|
||||
csharp_style_prefer_null_check_over_type_check = true:warning
|
||||
csharp_prefer_simple_using_statement = true:warning
|
||||
|
||||
# C++ Files
|
||||
|
||||
[*.{cpp,h,in}]
|
||||
curly_bracket_next_line = true
|
||||
indent_brace_style = Allman
|
||||
|
38
.github/ISSUE_TEMPLATE/bug-report.md
vendored
Normal file
38
.github/ISSUE_TEMPLATE/bug-report.md
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: File a bug report
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Your BTCPay Environment (please complete the following information):**
|
||||
- BTCPay Server Version: [available in the right bottom corner of footer]
|
||||
- Deployment Method: [e.g. Docker, Manual, Third-Party-host]
|
||||
- Browser: [e.g. Chrome, Safari]
|
||||
|
||||
**Logs (if applicable)**
|
||||
Basic logs can be found in Server Settings > Logs. More logs https://docs.btcpayserver.org/Troubleshooting/#2-looking-through-the-logs
|
||||
|
||||
**Setup Parameters**
|
||||
If you're reporting a deployment issue run `. btcpay-setup.sh -i` and paste the setup parameters here with your private information removed or obscured.
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
68
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
68
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@ -1,68 +0,0 @@
|
||||
name: 🐛 Bug Report
|
||||
description: File a bug report
|
||||
title: "[Bug]: "
|
||||
labels: ["bug"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this bug report! Please provide as much information as you can. It helps us better understand the problem and fix it faster.
|
||||
- type: textarea
|
||||
id: version
|
||||
attributes:
|
||||
label: What is your BTCPay version?
|
||||
description: You can see the version in the footer's bottom right corner
|
||||
placeholder: I'm running BTCPay v1.X.X.X
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: deployment
|
||||
attributes:
|
||||
label: How did you deploy BTCPay Server?
|
||||
description: Docker, manual, third-party host? Read more on deployment methods [here](https://docs.btcpayserver.org/Deployment/)
|
||||
placeholder: I'm running BTCPay Server on a...
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: what-happened
|
||||
attributes:
|
||||
label: What happened?
|
||||
description: A clear and concise description of what the bug is.
|
||||
placeholder: Tell us what you see!
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: reproduce
|
||||
attributes:
|
||||
label: How did you encounter this bug?
|
||||
description: Step by step describe how did you encounter the bug?
|
||||
placeholder: 1. I clicked X 2. Then I clicked Y 3. See error
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: logoutput
|
||||
attributes:
|
||||
label: Relevant log output
|
||||
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. Logs can be found in Server Settings > Logs. Here's how you can [troubleshoot an issue](https://docs.btcpayserver.org/Troubleshooting/)
|
||||
render: shell
|
||||
- type: textarea
|
||||
id: browser
|
||||
attributes:
|
||||
label: What browser do you use?
|
||||
description: Provide your browser and it's version. If you replicated issues on multiple browsers, let us know which ones.
|
||||
placeholder: For example Safari 15.00, Chrome 10.0, Tor, Edge, etc
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: additonal
|
||||
attributes:
|
||||
label: Additional information
|
||||
description: Feel free to provide additional information. Screenshots are always helpful.
|
||||
- type: checkboxes
|
||||
id: terms
|
||||
attributes:
|
||||
label: Are you sure this is a bug report?
|
||||
description: By submitting this report, you agree that this is not a support or a feature request. For general questions please read our [documentation](https://docs.btcpayserver.org). You can ask questions in [discussions](https://github.com/btcpayserver/btcpayserver/discussions) and [on our community chat](https://chat.btcpayserver.org) Beware of scammers we will never direct you to third-party sites for support or ask for sensitive information your private key especially. Ignore any bots and scammers replies to GitHub issues claiming to be support agents
|
||||
options:
|
||||
- label: I confirm this is a bug report
|
||||
required: true
|
18
.github/ISSUE_TEMPLATE/config.yml
vendored
18
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -1,17 +1,5 @@
|
||||
blank_issues_enabled: true
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: 💡 Request a feature
|
||||
url: https://github.com/btcpayserver/btcpayserver/discussions/categories/ideas-feature-requests
|
||||
about: Submit a feature request or vote on ideas posted by others. Features with most upvotes become roadmap candidates
|
||||
- name: 🧑💻 Ask a technical question
|
||||
url: https://github.com/btcpayserver/btcpayserver/discussions/new?category=technical-support
|
||||
about: If you're experiencing a technical problem post it to our community support forum
|
||||
- name: 🔌 Report a problem with a plugin
|
||||
url: https://github.com/btcpayserver/btcpayserver/discussions/new?category=plugins-integrations
|
||||
about: Experiencing a problem with a third-party plugin? Post it here and we will tag their developers to assist
|
||||
- name: 📝 Official Documentation
|
||||
url: https://docs.btcpayserver.org
|
||||
about: Check our documentation for answers to common questions
|
||||
- name: 💬 Community Support Chat
|
||||
- name: Community Support Chat
|
||||
url: https://chat.btcpayserver.org/
|
||||
about: Ask general questions and get community support in real-time
|
||||
about: Ask general questions and get community support in real-time.
|
||||
|
23
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
23
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest a new feature or enhancement
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Sketch/Image/Wireframe/Mockup**
|
||||
If applicable provide examples, wireframes, sketches or images to better explain your idea.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
2
.github/codeql/codeql-config.yml
vendored
2
.github/codeql/codeql-config.yml
vendored
@ -1,2 +0,0 @@
|
||||
paths-ignore:
|
||||
- 'BTCPayServer/wwwroot/vendor/**/*.js'
|
80
.github/workflows/codeql.yml
vendored
80
.github/workflows/codeql.yml
vendored
@ -1,80 +0,0 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
# Allow running tests manually. Usefull if scan failure, or need to rescan before next scheduled date.
|
||||
workflow_dispatch:
|
||||
# We scan only on a schedule for now, can uncomment the following to scan on commit or PR merge later on if deemed appropriate.
|
||||
# push:
|
||||
# branches: [ "master" ]
|
||||
# pull_request:
|
||||
# branches: [ "master" ]
|
||||
schedule:
|
||||
# Scan every Monday 06:00 UTC.
|
||||
- cron: '0 6 * * 1'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'javascript', 'csharp' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||
# Use only 'java' to analyze code written in Java, Kotlin or both
|
||||
# Use only 'javascript' to analyze code written in JavaScript, TypeScript or both
|
||||
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
config-file: ./.github/codeql/codeql-config.yml
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
|
||||
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||
# queries: security-extended,security-and-quality
|
||||
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
|
||||
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
||||
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
||||
|
||||
# - run: |
|
||||
# echo "Run, Build Application using script"
|
||||
# ./location_of_script_within_repo/buildscript.sh
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
11
.gitignore
vendored
11
.gitignore
vendored
@ -266,7 +266,6 @@ paket-files/
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
.run
|
||||
|
||||
# CodeRush
|
||||
.cr/
|
||||
@ -289,6 +288,10 @@ __pycache__/
|
||||
*.xsd.cs
|
||||
/BTCPayServer/Build/dockerfiles
|
||||
|
||||
# Bundling JS/CSS
|
||||
BTCPayServer/wwwroot/bundles/*
|
||||
!BTCPayServer/wwwroot/bundles/.gitignore
|
||||
|
||||
.vscode/*
|
||||
!.vscode/launch.json
|
||||
!.vscode/tasks.json
|
||||
@ -296,9 +299,3 @@ __pycache__/
|
||||
BTCPayServer/testpwd
|
||||
.DS_Store
|
||||
Packed Plugins
|
||||
Plugins/packed
|
||||
|
||||
BTCPayServer/wwwroot/swagger/v1/openapi.json
|
||||
BTCPayServer/appsettings.dev.json
|
||||
BTCPayServer.Tests/monero_wallet
|
||||
/BTCPayServer.Tests/NewBlocks.bat
|
||||
|
6
.run/Build and pack extensions.run.xml
Normal file
6
.run/Build and pack extensions.run.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Build and pack plugins" type="CompoundRunConfigurationType">
|
||||
<toRun name="Pack Test Plugin" type="DotNetProject" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
21
.run/Pack Test Extension.run.xml
Normal file
21
.run/Pack Test Extension.run.xml
Normal file
@ -0,0 +1,21 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Pack Test Plugin" type="DotNetProject" factoryName=".NET Project" singleton="false">
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/BTCPayServer.PluginPacker/bin/Debug/netcoreapp3.1/BTCPayServer.PluginPacker.dll" />
|
||||
<option name="PROGRAM_PARAMETERS" value="../../../../BTCPayServer.Plugins.Test\bin\Debug\netcoreapp3.1 BTCPayServer.Plugins.Test "../../../../Packed Plugins"" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/BTCPayServer.PluginPacker/bin/Debug/netcoreapp3.1" />
|
||||
<option name="PASS_PARENT_ENVS" value="1" />
|
||||
<option name="USE_EXTERNAL_CONSOLE" value="0" />
|
||||
<option name="USE_MONO" value="0" />
|
||||
<option name="RUNTIME_ARGUMENTS" value="" />
|
||||
<option name="PROJECT_PATH" value="$PROJECT_DIR$/BTCPayServer.PluginPacker/BTCPayServer.PluginPacker.csproj" />
|
||||
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
|
||||
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
|
||||
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
|
||||
<option name="PROJECT_KIND" value="DotNetCore" />
|
||||
<option name="PROJECT_TFM" value=".NETCoreApp,Version=v3.1" />
|
||||
<method v="2">
|
||||
<option name="Build" default="false" projectName="BTCPayServer.Plugins.Test" projectPath="C:\Git\btcpayserver\BTCPayServer.Plugins.Test\BTCPayServer.Plugins.Test.csproj" />
|
||||
<option name="Build" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
4
.vscode/launch.json
vendored
4
.vscode/launch.json
vendored
@ -10,14 +10,14 @@
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
// If you have changed target frameworks, make sure to update the program path.
|
||||
"program": "${workspaceFolder}/BTCPayServer/bin/Debug/net8.0/BTCPayServer.dll",
|
||||
"program": "${workspaceFolder}/BTCPayServer/bin/Debug/netcoreapp3.1/BTCPayServer.dll",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}/BTCPayServer",
|
||||
"stopAtEntry": false,
|
||||
// Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser
|
||||
"serverReadyAction": {
|
||||
"action": "openExternally",
|
||||
"pattern": "\\bNow listening on:\\s+(https?://\\S+)"
|
||||
"pattern": "\\bListening on\\s+(https?://\\S+)"
|
||||
},
|
||||
"env": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
|
@ -30,12 +30,4 @@
|
||||
<ItemGroup>
|
||||
<None Include="icon.png" Pack="true" PackagePath="\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="HtmlSanitizer" Version="8.0.838" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.11" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.11" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BTCPayServer.Client\BTCPayServer.Client.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -1,18 +0,0 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BTCPayServer.Abstractions
|
||||
{
|
||||
public class CamelCaseSerializerSettings
|
||||
{
|
||||
static CamelCaseSerializerSettings()
|
||||
{
|
||||
Settings = new JsonSerializerSettings()
|
||||
{
|
||||
ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver()
|
||||
};
|
||||
Serializer = JsonSerializer.Create(Settings);
|
||||
}
|
||||
public static readonly JsonSerializerSettings Settings;
|
||||
public static readonly JsonSerializer Serializer;
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
using System.IO;
|
||||
|
||||
namespace BTCPayServer.Configuration
|
||||
{
|
||||
public class DataDirectories
|
||||
{
|
||||
public string DataDir { get; set; }
|
||||
public string PluginDir { get; set; }
|
||||
public string TempStorageDir { get; set; }
|
||||
public string StorageDir { get; set; }
|
||||
public string TempDir { get; set; }
|
||||
public string LangsDir { get; set; }
|
||||
|
||||
public string ToDatadirFullPath(string path)
|
||||
{
|
||||
if (Path.IsPathRooted(path))
|
||||
return path;
|
||||
return Path.Combine(DataDir, path);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
namespace BTCPayServer.Abstractions.Constants
|
||||
namespace BTCPayServer.Security
|
||||
{
|
||||
public class AuthenticationSchemes
|
||||
{
|
||||
|
@ -1,7 +0,0 @@
|
||||
namespace BTCPayServer.Abstractions.Constants;
|
||||
|
||||
public class WellKnownTempData
|
||||
{
|
||||
public const string SuccessMessage = nameof(SuccessMessage);
|
||||
public const string ErrorMessage = nameof(ErrorMessage);
|
||||
}
|
@ -1,94 +0,0 @@
|
||||
using System;
|
||||
using BTCPayServer.Abstractions.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Npgsql;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Migrations;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Migrations.Operations;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Contracts
|
||||
{
|
||||
public abstract class BaseDbContextFactory<T> where T : DbContext
|
||||
{
|
||||
private readonly IOptions<DatabaseOptions> _options;
|
||||
private readonly string _migrationTableName;
|
||||
|
||||
public BaseDbContextFactory(IOptions<DatabaseOptions> options, string migrationTableName)
|
||||
{
|
||||
_options = options;
|
||||
_migrationTableName = migrationTableName;
|
||||
}
|
||||
|
||||
public T CreateContext() => CreateContext(null);
|
||||
public abstract T CreateContext(Action<NpgsqlDbContextOptionsBuilder> npgsqlOptionsAction = null);
|
||||
class CustomNpgsqlMigrationsSqlGenerator : NpgsqlMigrationsSqlGenerator
|
||||
{
|
||||
#pragma warning disable EF1001 // Internal EF Core API usage.
|
||||
public CustomNpgsqlMigrationsSqlGenerator(MigrationsSqlGeneratorDependencies dependencies, Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure.Internal.INpgsqlSingletonOptions opts) : base(dependencies, opts)
|
||||
#pragma warning restore EF1001 // Internal EF Core API usage.
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Generate(NpgsqlCreateDatabaseOperation operation, IModel model, MigrationCommandListBuilder builder)
|
||||
{
|
||||
builder
|
||||
.Append("CREATE DATABASE ")
|
||||
.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(operation.Name));
|
||||
|
||||
// POSTGRES gotcha: Indexed Text column (even if PK) are not used if we are not using C locale
|
||||
builder
|
||||
.Append(" TEMPLATE ")
|
||||
.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier("template0"));
|
||||
|
||||
builder
|
||||
.Append(" LC_CTYPE ")
|
||||
.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier("C"));
|
||||
|
||||
builder
|
||||
.Append(" LC_COLLATE ")
|
||||
.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier("C"));
|
||||
|
||||
builder
|
||||
.Append(" ENCODING ")
|
||||
.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier("UTF8"));
|
||||
|
||||
if (operation.Tablespace != null)
|
||||
{
|
||||
builder
|
||||
.Append(" TABLESPACE ")
|
||||
.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(operation.Tablespace));
|
||||
}
|
||||
|
||||
builder.AppendLine(Dependencies.SqlGenerationHelper.StatementTerminator);
|
||||
|
||||
EndStatement(builder, suppressTransaction: true);
|
||||
}
|
||||
}
|
||||
|
||||
public void ConfigureBuilder(DbContextOptionsBuilder builder) => ConfigureBuilder(builder, null);
|
||||
public void ConfigureBuilder(DbContextOptionsBuilder builder, Action<NpgsqlDbContextOptionsBuilder> npgsqlOptionsAction = null)
|
||||
{
|
||||
builder
|
||||
.UseNpgsql(_options.Value.ConnectionString, o =>
|
||||
{
|
||||
o.EnableRetryOnFailure(10);
|
||||
o.SetPostgresVersion(12, 0);
|
||||
npgsqlOptionsAction?.Invoke(o);
|
||||
var mainSearchPath = GetSearchPath(_options.Value.ConnectionString);
|
||||
var schemaPrefix = string.IsNullOrEmpty(_migrationTableName) ? "__EFMigrationsHistory" : _migrationTableName;
|
||||
o.MigrationsHistoryTable(schemaPrefix, mainSearchPath);
|
||||
})
|
||||
.ReplaceService<IMigrationsSqlGenerator, CustomNpgsqlMigrationsSqlGenerator>();
|
||||
}
|
||||
|
||||
private string GetSearchPath(string connectionString)
|
||||
{
|
||||
var connectionStringBuilder = new NpgsqlConnectionStringBuilder(connectionString);
|
||||
var searchPaths = connectionStringBuilder.SearchPath?.Split(',');
|
||||
return searchPaths is not { Length: > 0 } ? null : searchPaths[0];
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Contracts
|
||||
{
|
||||
public interface IBTCPayServerClientFactory
|
||||
{
|
||||
Task<BTCPayServerClient> Create(string userId, params string[] storeIds);
|
||||
Task<BTCPayServerClient> Create(string userId, string[] storeIds, HttpContext httpRequest);
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@ using BTCPayServer.Abstractions.Converters;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Contracts
|
||||
namespace BTCPayServer.Contracts
|
||||
{
|
||||
public interface IBTCPayServerPlugin
|
||||
{
|
||||
@ -28,5 +28,5 @@ namespace BTCPayServer.Abstractions.Contracts
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,19 +0,0 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using BTCPayServer.Abstractions.Models;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Contracts;
|
||||
|
||||
public interface IFileService
|
||||
{
|
||||
Task<bool> IsAvailable();
|
||||
Task<IStoredFile> AddFile(IFormFile file, string userId);
|
||||
Task<IStoredFile> AddFile(Uri file, string userId);
|
||||
Task<string?> GetFileUrl(Uri baseUri, string fileId);
|
||||
Task<string?> GetTemporaryFileUrl(Uri baseUri, string fileId, DateTimeOffset expiry,
|
||||
bool isDownload);
|
||||
Task RemoveFile(string fileId, string userId);
|
||||
Task<UploadImageResultModel> UploadImage(IFormFile file, string userId, long maxFileSizeInBytes = 1_000_000);
|
||||
}
|
@ -1,13 +1,13 @@
|
||||
using System;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Contracts
|
||||
namespace BTCPayServer.Contracts
|
||||
{
|
||||
public abstract class BaseNotification
|
||||
{
|
||||
public abstract string Identifier { get; }
|
||||
public abstract string NotificationType { get; }
|
||||
}
|
||||
|
||||
|
||||
public interface INotificationHandler
|
||||
{
|
||||
string NotificationType { get; }
|
||||
@ -15,16 +15,13 @@ namespace BTCPayServer.Abstractions.Contracts
|
||||
public (string identifier, string name)[] Meta { get; }
|
||||
void FillViewModel(object notification, NotificationViewModel vm);
|
||||
}
|
||||
|
||||
|
||||
public class NotificationViewModel
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Identifier { get; set; }
|
||||
public string Type { get; set; }
|
||||
public DateTimeOffset Created { get; set; }
|
||||
public string Body { get; set; }
|
||||
public string ActionLink { get; set; }
|
||||
public bool Seen { get; set; }
|
||||
public string StoreId { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +0,0 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Contracts
|
||||
{
|
||||
public interface IPluginHookAction
|
||||
{
|
||||
public string Hook { get; }
|
||||
Task Execute(object args);
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Contracts
|
||||
{
|
||||
public interface IPluginHookFilter
|
||||
{
|
||||
public string Hook { get; }
|
||||
|
||||
Task<object> Execute(object args);
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Contracts
|
||||
{
|
||||
public interface IPluginHookService
|
||||
{
|
||||
Task ApplyAction(string hook, object args);
|
||||
Task<object> ApplyFilter(string hook, object args);
|
||||
|
||||
event EventHandler<(string hook, object args)> ActionInvoked;
|
||||
event EventHandler<(string hook, object args)> FilterInvoked;
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
#nullable enable
|
||||
namespace BTCPayServer.Abstractions.Contracts;
|
||||
|
||||
public interface IScopeProvider
|
||||
{
|
||||
string? GetCurrentStoreId();
|
||||
}
|
@ -1,13 +1,12 @@
|
||||
#nullable enable
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Contracts
|
||||
namespace BTCPayServer.Services
|
||||
{
|
||||
public interface ISettingsRepository
|
||||
{
|
||||
Task<T?> GetSettingAsync<T>(string? name = null) where T : class;
|
||||
Task UpdateSetting<T>(T obj, string? name = null) where T : class;
|
||||
Task<T> WaitSettingsChanged<T>(CancellationToken cancellationToken = default) where T : class;
|
||||
Task<T> GetSettingAsync<T>(string name = null);
|
||||
Task UpdateSetting<T>(T obj, string name = null);
|
||||
Task<T> WaitSettingsChanged<T>(CancellationToken cancellationToken = default);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Contracts
|
||||
namespace BTCPayServer.Hosting
|
||||
{
|
||||
public interface IStartupTask
|
||||
{
|
||||
|
21
BTCPayServer.Abstractions/Contracts/IStoreNavExtension.cs
Normal file
21
BTCPayServer.Abstractions/Contracts/IStoreNavExtension.cs
Normal file
@ -0,0 +1,21 @@
|
||||
namespace BTCPayServer.Contracts
|
||||
{
|
||||
public interface IUIExtension
|
||||
{
|
||||
string Partial { get; }
|
||||
|
||||
string Location { get; }
|
||||
}
|
||||
|
||||
public class UIExtension: IUIExtension
|
||||
{
|
||||
public UIExtension(string partial, string location)
|
||||
{
|
||||
Partial = partial;
|
||||
Location = location;
|
||||
}
|
||||
|
||||
public string Partial { get; }
|
||||
public string Location { get; }
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Contracts;
|
||||
|
||||
public interface IStoreRepository
|
||||
{
|
||||
Task<T?> GetSettingAsync<T>(string storeId, string name) where T : class;
|
||||
Task<Dictionary<string, T?>> GetSettingsAsync<T>(string name) where T : class;
|
||||
Task UpdateSetting<T>(string storeId, string name, T obj) where T : class;
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Contracts;
|
||||
|
||||
public interface IStoredFile
|
||||
{
|
||||
string Id { get; set; }
|
||||
string FileName { get; set; }
|
||||
string StorageFileName { get; set; }
|
||||
DateTime Timestamp { get; set; }
|
||||
string ApplicationUserId { get; set; }
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Contracts;
|
||||
|
||||
public interface ISwaggerProvider
|
||||
{
|
||||
Task<JObject> Fetch();
|
||||
}
|
@ -1,18 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Contracts
|
||||
namespace BTCPayServer.Contracts
|
||||
{
|
||||
public interface ISyncSummaryProvider
|
||||
{
|
||||
bool AllAvailable();
|
||||
|
||||
string Partial { get; }
|
||||
IEnumerable<ISyncStatus> GetStatuses();
|
||||
}
|
||||
|
||||
public interface ISyncStatus
|
||||
{
|
||||
public string PaymentMethodId { get; set; }
|
||||
public bool Available { get; }
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +0,0 @@
|
||||
namespace BTCPayServer.Abstractions.Contracts
|
||||
{
|
||||
public interface IUIExtension
|
||||
{
|
||||
string Partial { get; }
|
||||
|
||||
string Location { get; }
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using NBitcoin;
|
||||
|
||||
namespace BTCPayServer.Payments.PayJoin;
|
||||
|
||||
public interface IUTXOLocker
|
||||
{
|
||||
Task<bool> TryLock(OutPoint outpoint);
|
||||
Task<bool> TryUnlock(params OutPoint[] outPoints);
|
||||
Task<bool> TryLockInputs(OutPoint[] outPoints);
|
||||
Task<HashSet<OutPoint>> FindLocks(OutPoint[] outpoints);
|
||||
}
|
20
BTCPayServer.Abstractions/Extensions/Extensions.cs
Normal file
20
BTCPayServer.Abstractions/Extensions/Extensions.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using System.Text.Json;
|
||||
using BTCPayServer.Models;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public static class SetStatusMessageModelExtensions
|
||||
{
|
||||
public static void SetStatusMessageModel(this ITempDataDictionary tempData, StatusMessageModel statusMessage)
|
||||
{
|
||||
if (statusMessage == null)
|
||||
{
|
||||
tempData.Remove("StatusMessageModel");
|
||||
return;
|
||||
}
|
||||
|
||||
tempData["StatusMessageModel"] = JsonSerializer.Serialize(statusMessage, new JsonSerializerOptions());
|
||||
}
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using BTCPayServer.Client.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Extensions;
|
||||
|
||||
public static class GreenfieldExtensions
|
||||
{
|
||||
public static IActionResult UserNotFound(this ControllerBase ctrl)
|
||||
{
|
||||
return ctrl.CreateAPIError(404, "user-not-found", "The user was not found");
|
||||
}
|
||||
public static IActionResult CreateValidationError(this ControllerBase controller, ModelStateDictionary modelState)
|
||||
{
|
||||
return controller.UnprocessableEntity(modelState.ToGreenfieldValidationError());
|
||||
}
|
||||
|
||||
public static List<GreenfieldValidationError> ToGreenfieldValidationError(this ModelStateDictionary modelState)
|
||||
{
|
||||
List<GreenfieldValidationError> errors = new List<GreenfieldValidationError>();
|
||||
foreach (var error in modelState)
|
||||
{
|
||||
foreach (var errorMessage in error.Value.Errors)
|
||||
{
|
||||
errors.Add(new GreenfieldValidationError(error.Key, errorMessage.ErrorMessage));
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
public static IActionResult CreateAPIError(this ControllerBase controller, string errorCode, string errorMessage)
|
||||
{
|
||||
return controller.BadRequest(new GreenfieldAPIError(errorCode, errorMessage));
|
||||
}
|
||||
|
||||
public static IActionResult CreateAPIError(this ControllerBase controller, int httpCode, string errorCode, string errorMessage)
|
||||
{
|
||||
return controller.StatusCode(httpCode, new GreenfieldAPIError(errorCode, errorMessage));
|
||||
}
|
||||
|
||||
public static IActionResult CreateAPIPermissionError(this ControllerBase controller, string missingPermission, string message = null)
|
||||
{
|
||||
return controller.StatusCode(403, new GreenfieldPermissionAPIError(missingPermission, message));
|
||||
}
|
||||
}
|
@ -1,131 +0,0 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Extensions;
|
||||
|
||||
public static class HttpRequestExtensions
|
||||
{
|
||||
public static bool IsOnion(this HttpRequest request)
|
||||
{
|
||||
if (request?.Host.Host == null)
|
||||
return false;
|
||||
return request.Host.Host.EndsWith(".onion", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public static string GetAbsoluteRoot(this HttpRequest request)
|
||||
{
|
||||
return string.Concat(
|
||||
request.Scheme,
|
||||
"://",
|
||||
request.Host.ToUriComponent(),
|
||||
request.PathBase.ToUriComponent());
|
||||
}
|
||||
|
||||
public static Uri GetAbsoluteRootUri(this HttpRequest request)
|
||||
{
|
||||
return new Uri(request.GetAbsoluteRoot());
|
||||
}
|
||||
|
||||
public static string GetCurrentUrl(this HttpRequest request)
|
||||
{
|
||||
return string.Concat(
|
||||
request.Scheme,
|
||||
"://",
|
||||
request.Host.ToUriComponent(),
|
||||
request.PathBase.ToUriComponent(),
|
||||
request.Path.ToUriComponent());
|
||||
}
|
||||
|
||||
public static string GetCurrentUrlWithQueryString(this HttpRequest request)
|
||||
{
|
||||
return string.Concat(
|
||||
request.Scheme,
|
||||
"://",
|
||||
request.Host.ToUriComponent(),
|
||||
request.PathBase.ToUriComponent(),
|
||||
request.Path.ToUriComponent(),
|
||||
request.QueryString.ToUriComponent());
|
||||
}
|
||||
|
||||
public static string GetCurrentPath(this HttpRequest request)
|
||||
{
|
||||
return string.Concat(
|
||||
request.PathBase.ToUriComponent(),
|
||||
request.Path.ToUriComponent());
|
||||
}
|
||||
|
||||
public static string GetCurrentPathWithQueryString(this HttpRequest request)
|
||||
{
|
||||
return request.PathBase + request.Path + request.QueryString;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If 'toto' and RootPath is 'rootpath' returns '/rootpath/toto'
|
||||
/// If 'toto' and RootPath is empty returns '/toto'
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetRelativePath(this HttpRequest request, string path)
|
||||
{
|
||||
if (path.Length > 0 && path[0] != '/')
|
||||
path = $"/{path}";
|
||||
return string.Concat(
|
||||
request.PathBase.ToUriComponent(),
|
||||
path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If 'https://example.com/toto' returns 'https://example.com/toto'
|
||||
/// If 'toto' and RootPath is 'rootpath' returns '/rootpath/toto'
|
||||
/// If 'toto' and RootPath is empty returns '/toto'
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetRelativePathOrAbsolute(this HttpRequest request, string path)
|
||||
{
|
||||
if (!Uri.TryCreate(path, UriKind.RelativeOrAbsolute, out var uri) ||
|
||||
uri.IsAbsoluteUri)
|
||||
return path;
|
||||
|
||||
if (path.Length > 0 && path[0] != '/')
|
||||
path = $"/{path}";
|
||||
return string.Concat(
|
||||
request.PathBase.ToUriComponent(),
|
||||
path);
|
||||
}
|
||||
|
||||
public static string GetAbsoluteUri(this HttpRequest request, string redirectUrl)
|
||||
{
|
||||
bool isRelative =
|
||||
(redirectUrl.Length > 0 && redirectUrl[0] == '/')
|
||||
|| !new Uri(redirectUrl, UriKind.RelativeOrAbsolute).IsAbsoluteUri;
|
||||
return isRelative ? request.GetAbsoluteRoot() + redirectUrl : redirectUrl;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will return an absolute URL.
|
||||
/// If `relativeOrAbsolute` is absolute, returns it.
|
||||
/// If `relativeOrAbsolute` is relative, send absolute url based on the HOST of this request (without PathBase)
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="relativeOrAbsolte"></param>
|
||||
/// <returns></returns>
|
||||
public static Uri GetAbsoluteUriNoPathBase(this HttpRequest request, Uri relativeOrAbsolute = null)
|
||||
{
|
||||
if (relativeOrAbsolute == null)
|
||||
{
|
||||
return new Uri(string.Concat(
|
||||
request.Scheme,
|
||||
"://",
|
||||
request.Host.ToUriComponent()), UriKind.Absolute);
|
||||
}
|
||||
if (relativeOrAbsolute.IsAbsoluteUri)
|
||||
return relativeOrAbsolute;
|
||||
return new Uri(string.Concat(
|
||||
request.Scheme,
|
||||
"://",
|
||||
request.Host.ToUriComponent()) + relativeOrAbsolute.ToString().WithStartingSlash(), UriKind.Absolute);
|
||||
}
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
using System.Text.Json;
|
||||
using BTCPayServer.Abstractions.Constants;
|
||||
using BTCPayServer.Abstractions.Models;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Extensions;
|
||||
|
||||
public static class SetStatusMessageModelExtensions
|
||||
{
|
||||
public static void SetStatusSuccess(this ITempDataDictionary tempData, string statusMessage)
|
||||
{
|
||||
tempData.SetStatusMessageModel(new StatusMessageModel
|
||||
{
|
||||
Severity = StatusMessageModel.StatusSeverity.Success,
|
||||
Message = statusMessage
|
||||
});
|
||||
}
|
||||
public static void SetStatusMessageModel(this ITempDataDictionary tempData, StatusMessageModel statusMessage)
|
||||
{
|
||||
if (statusMessage == null)
|
||||
{
|
||||
tempData.Remove("StatusMessageModel");
|
||||
return;
|
||||
}
|
||||
|
||||
tempData["StatusMessageModel"] = JsonSerializer.Serialize(statusMessage, new JsonSerializerOptions());
|
||||
}
|
||||
|
||||
public static StatusMessageModel GetStatusMessageModel(this ITempDataDictionary tempData)
|
||||
{
|
||||
tempData.TryGetValue(WellKnownTempData.SuccessMessage, out var successMessage);
|
||||
tempData.TryGetValue(WellKnownTempData.ErrorMessage, out var errorMessage);
|
||||
tempData.TryGetValue("StatusMessageModel", out var model);
|
||||
if (successMessage != null || errorMessage != null)
|
||||
{
|
||||
var parsedModel = new StatusMessageModel
|
||||
{
|
||||
Message = (string)successMessage ?? (string)errorMessage,
|
||||
Severity = successMessage != null ? StatusMessageModel.StatusSeverity.Success : StatusMessageModel.StatusSeverity.Error
|
||||
};
|
||||
return parsedModel;
|
||||
}
|
||||
if (model is string str)
|
||||
{
|
||||
return JObject.Parse(str).ToObject<StatusMessageModel>();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static bool HasStatusMessage(this ITempDataDictionary tempData)
|
||||
{
|
||||
return (tempData.Peek(WellKnownTempData.SuccessMessage) ??
|
||||
tempData.Peek(WellKnownTempData.ErrorMessage) ??
|
||||
tempData.Peek("StatusMessageModel")) != null;
|
||||
}
|
||||
|
||||
public static bool HasErrorMessage(this ITempDataDictionary tempData)
|
||||
{
|
||||
return GetStatusMessageModel(tempData)?.Severity == StatusMessageModel.StatusSeverity.Error;
|
||||
}
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
using BTCPayServer.Abstractions.Contracts;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using BTCPayServer.Hosting;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Extensions
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
{
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
|
@ -1,43 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Extensions;
|
||||
|
||||
public static class StringExtensions
|
||||
{
|
||||
public static bool IsValidFileName(this string fileName)
|
||||
{
|
||||
return !fileName.ToCharArray().Any(c => Path.GetInvalidFileNameChars().Contains(c)
|
||||
|| c == Path.AltDirectorySeparatorChar
|
||||
|| c == Path.DirectorySeparatorChar
|
||||
|| c == Path.PathSeparator
|
||||
|| c == '\\');
|
||||
}
|
||||
|
||||
public static string Truncate(this string value, int maxLength)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
return value;
|
||||
return value.Length <= maxLength ? value : value.Substring(0, maxLength);
|
||||
}
|
||||
|
||||
public static string WithTrailingSlash(this string str)
|
||||
{
|
||||
if (str.EndsWith("/", StringComparison.InvariantCulture))
|
||||
return str;
|
||||
return str + "/";
|
||||
}
|
||||
public static string WithStartingSlash(this string str)
|
||||
{
|
||||
if (str.StartsWith("/", StringComparison.InvariantCulture))
|
||||
return str;
|
||||
return $"/{str}";
|
||||
}
|
||||
public static string WithoutEndingSlash(this string str)
|
||||
{
|
||||
if (str.EndsWith("/", StringComparison.InvariantCulture))
|
||||
return str.Substring(0, str.Length - 1);
|
||||
return str;
|
||||
}
|
||||
}
|
@ -1,199 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Html;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Extensions
|
||||
{
|
||||
public static class ViewsRazor
|
||||
{
|
||||
private const string ACTIVE_CATEGORY_KEY = "ActiveCategory";
|
||||
private const string ACTIVE_PAGE_KEY = "ActivePage";
|
||||
private const string ACTIVE_ID_KEY = "ActiveId";
|
||||
private const string ACTIVE_CLASS = "active";
|
||||
|
||||
public enum DateDisplayFormat
|
||||
{
|
||||
Localized,
|
||||
Relative
|
||||
}
|
||||
|
||||
public static void SetBlazorAllowed(this ViewDataDictionary viewData, bool allowed)
|
||||
{
|
||||
viewData["BlazorAllowed"] = allowed;
|
||||
}
|
||||
public static bool IsBlazorAllowed(this ViewDataDictionary viewData)
|
||||
{
|
||||
return viewData["BlazorAllowed"] is not false;
|
||||
}
|
||||
|
||||
public static void SetActivePage<T>(this ViewDataDictionary viewData, T activePage, string title = null, string activeId = null)
|
||||
where T : IConvertible
|
||||
{
|
||||
SetActivePage(viewData, activePage.ToString(), activePage.GetType().ToString(), title, activeId);
|
||||
}
|
||||
|
||||
public static void SetActivePage(this ViewDataDictionary viewData, string activePage, string category, string title = null, string activeId = null)
|
||||
{
|
||||
// Page Title
|
||||
viewData["Title"] = title ?? activePage;
|
||||
// Navigation
|
||||
viewData[ACTIVE_PAGE_KEY] = activePage;
|
||||
viewData[ACTIVE_ID_KEY] = activeId;
|
||||
SetActiveCategory(viewData, category);
|
||||
}
|
||||
|
||||
public static void SetActiveCategory<T>(this ViewDataDictionary viewData, T activeCategory)
|
||||
{
|
||||
SetActiveCategory(viewData, activeCategory.ToString());
|
||||
}
|
||||
|
||||
public static void SetActiveCategory(this ViewDataDictionary viewData, string activeCategory)
|
||||
{
|
||||
viewData[ACTIVE_CATEGORY_KEY] = activeCategory;
|
||||
}
|
||||
|
||||
public static bool IsCategoryActive(this ViewDataDictionary viewData, string category, object id = null)
|
||||
{
|
||||
if (!viewData.ContainsKey(ACTIVE_CATEGORY_KEY)) return false;
|
||||
var activeId = viewData[ACTIVE_ID_KEY];
|
||||
var activeCategory = viewData[ACTIVE_CATEGORY_KEY]?.ToString();
|
||||
var categoryMatch = category.Equals(activeCategory, StringComparison.InvariantCultureIgnoreCase);
|
||||
var idMatch = id == null || activeId == null || id.Equals(activeId);
|
||||
return categoryMatch && idMatch;
|
||||
}
|
||||
|
||||
public static bool IsCategoryActive<T>(this ViewDataDictionary viewData, T category, object id = null)
|
||||
{
|
||||
return IsCategoryActive(viewData, category.ToString(), id);
|
||||
}
|
||||
|
||||
public static bool IsPageActive(this ViewDataDictionary viewData, string page, string category, object id = null)
|
||||
{
|
||||
if (!viewData.ContainsKey(ACTIVE_PAGE_KEY)) return false;
|
||||
var activeId = viewData[ACTIVE_ID_KEY];
|
||||
var activePage = viewData[ACTIVE_PAGE_KEY]?.ToString();
|
||||
var activeCategory = viewData[ACTIVE_CATEGORY_KEY]?.ToString();
|
||||
var categoryAndPageMatch = page.Equals(activePage, StringComparison.InvariantCultureIgnoreCase) &&
|
||||
(category == null || activeCategory != null && activeCategory.Equals(category, StringComparison.InvariantCultureIgnoreCase));
|
||||
var idMatch = id == null || activeId == null || id.Equals(activeId);
|
||||
return categoryAndPageMatch && idMatch;
|
||||
}
|
||||
|
||||
public static bool IsPageActive<T>(this ViewDataDictionary viewData, IEnumerable<T> pages, object id = null)
|
||||
where T : IConvertible
|
||||
{
|
||||
return pages.Any(page => ActivePageClass(viewData, page.ToString(), page.GetType().ToString(), id) == ACTIVE_CLASS);
|
||||
}
|
||||
|
||||
public static string ActiveCategoryClass<T>(this ViewDataDictionary viewData, T category, object id = null)
|
||||
{
|
||||
return ActiveCategoryClass(viewData, category.ToString(), id);
|
||||
}
|
||||
|
||||
public static string ActiveCategoryClass(this ViewDataDictionary viewData, string category, object id = null)
|
||||
{
|
||||
return IsCategoryActive(viewData, category, id) ? ACTIVE_CLASS : null;
|
||||
}
|
||||
|
||||
public static string ActivePageClass<T>(this ViewDataDictionary viewData, T page, object id = null)
|
||||
where T : IConvertible
|
||||
{
|
||||
return ActivePageClass(viewData, page.ToString(), page.GetType().ToString(), id);
|
||||
}
|
||||
|
||||
public static string ActivePageClass(this ViewDataDictionary viewData, string page, string category, object id = null)
|
||||
{
|
||||
return IsPageActive(viewData, page, category, id) ? ACTIVE_CLASS : null;
|
||||
}
|
||||
|
||||
public static string ActivePageClass<T>(this ViewDataDictionary viewData, IEnumerable<T> pages, object id = null) where T : IConvertible
|
||||
{
|
||||
return IsPageActive(viewData, pages, id) ? ACTIVE_CLASS : null;
|
||||
}
|
||||
|
||||
[Obsolete("Use ActiveCategoryClass instead")]
|
||||
public static string IsActiveCategory<T>(this ViewDataDictionary viewData, T category, object id = null)
|
||||
{
|
||||
return ActiveCategoryClass(viewData, category, id);
|
||||
}
|
||||
|
||||
[Obsolete("Use ActiveCategoryClass instead")]
|
||||
public static string IsActiveCategory(this ViewDataDictionary viewData, string category, object id = null)
|
||||
{
|
||||
return ActiveCategoryClass(viewData, category, id);
|
||||
}
|
||||
|
||||
[Obsolete("Use ActivePageClass instead")]
|
||||
public static string IsActivePage<T>(this ViewDataDictionary viewData, T page, object id = null) where T : IConvertible
|
||||
{
|
||||
return ActivePageClass(viewData, page, id);
|
||||
}
|
||||
|
||||
[Obsolete("Use ActivePageClass instead")]
|
||||
public static string IsActivePage<T>(this ViewDataDictionary viewData, IEnumerable<T> pages, object id = null) where T : IConvertible
|
||||
{
|
||||
return ActivePageClass(viewData, pages, id);
|
||||
}
|
||||
|
||||
[Obsolete("Use ActivePageClass instead")]
|
||||
public static string IsActivePage(this ViewDataDictionary viewData, string page, string category, object id = null)
|
||||
{
|
||||
return ActivePageClass(viewData, page, category, id);
|
||||
}
|
||||
|
||||
public static HtmlString ToBrowserDate(this DateTimeOffset date, string netFormat, string jsDateFormat = "short", string jsTimeFormat = "short")
|
||||
{
|
||||
var dateTime = date.ToString("o", CultureInfo.InvariantCulture);
|
||||
var displayDate = date.ToString(netFormat, CultureInfo.InvariantCulture);
|
||||
var tooltip = dateTime.Replace("T", " ");
|
||||
return new HtmlString($"<time datetime=\"{dateTime}\" data-date-style=\"{jsDateFormat}\" data-time-style=\"{jsTimeFormat}\" data-initial=\"localized\" data-bs-toggle=\"tooltip\" data-bs-title=\"{tooltip}\">{displayDate}</time>");
|
||||
}
|
||||
|
||||
public static HtmlString ToBrowserDate(this DateTimeOffset date, DateDisplayFormat format = DateDisplayFormat.Localized)
|
||||
{
|
||||
var relative = date.ToTimeAgo();
|
||||
var initial = format.ToString().ToLower();
|
||||
var dateTime = date.ToString("o", CultureInfo.InvariantCulture);
|
||||
var displayDate = format == DateDisplayFormat.Relative ? relative : date.ToString("g", CultureInfo.InvariantCulture);
|
||||
return new HtmlString($"<time datetime=\"{dateTime}\" data-relative=\"{relative}\" data-initial=\"{initial}\">{displayDate}</time>");
|
||||
}
|
||||
|
||||
public static HtmlString ToBrowserDate(this DateTime date, DateDisplayFormat format = DateDisplayFormat.Localized)
|
||||
{
|
||||
var relative = date.ToTimeAgo();
|
||||
var initial = format.ToString().ToLower();
|
||||
var dateTime = date.ToString("o", CultureInfo.InvariantCulture);
|
||||
var displayDate = format == DateDisplayFormat.Relative ? relative : date.ToString("g", CultureInfo.InvariantCulture);
|
||||
return new HtmlString($"<time datetime=\"{dateTime}\" data-relative=\"{relative}\" data-initial=\"{initial}\">{displayDate}</time>");
|
||||
}
|
||||
|
||||
public static string ToTimeAgo(this DateTimeOffset date) => (DateTimeOffset.UtcNow - date).ToTimeAgo();
|
||||
|
||||
public static string ToTimeAgo(this DateTime date) => (DateTimeOffset.UtcNow - date).ToTimeAgo();
|
||||
|
||||
public static string ToTimeAgo(this TimeSpan diff) => diff.TotalSeconds > 0 ? $"{diff.TimeString()} ago" : $"in {diff.Negate().TimeString()}";
|
||||
|
||||
public static string TimeString(this TimeSpan timeSpan)
|
||||
{
|
||||
if (timeSpan.TotalMinutes < 1)
|
||||
{
|
||||
return $"{(int)timeSpan.TotalSeconds} second{Plural((int)timeSpan.TotalSeconds)}";
|
||||
}
|
||||
if (timeSpan.TotalHours < 1)
|
||||
{
|
||||
return $"{(int)timeSpan.TotalMinutes} minute{Plural((int)timeSpan.TotalMinutes)}";
|
||||
}
|
||||
return timeSpan.Days < 1
|
||||
? $"{(int)timeSpan.TotalHours} hour{Plural((int)timeSpan.TotalHours)}"
|
||||
: $"{(int)timeSpan.TotalDays} day{Plural((int)timeSpan.TotalDays)}";
|
||||
}
|
||||
|
||||
private static string Plural(int value)
|
||||
{
|
||||
return value == 1 ? string.Empty : "s";
|
||||
}
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Form;
|
||||
|
||||
public class AlertMessage
|
||||
{
|
||||
// Corresponds to the Bootstrap CSS "alert alert-xxx" messages:
|
||||
// Success = green
|
||||
// Warning = orange
|
||||
// Danger = red
|
||||
// Info = blue
|
||||
public enum AlertMessageType
|
||||
{
|
||||
Success,
|
||||
Warning,
|
||||
Danger,
|
||||
Info
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public AlertMessageType Type;
|
||||
|
||||
// The translated message to be shown to the user
|
||||
public string Message;
|
||||
|
||||
public AlertMessage()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public AlertMessage(AlertMessageType type, string message)
|
||||
{
|
||||
this.Type = type;
|
||||
this.Message = message;
|
||||
}
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Form;
|
||||
|
||||
public class Field
|
||||
{
|
||||
public static Field Create(string label, string name, string value, bool required, string helpText, string type = "text")
|
||||
{
|
||||
return new Field
|
||||
{
|
||||
Label = label,
|
||||
Name = name,
|
||||
Value = value,
|
||||
OriginalValue = value,
|
||||
Required = required,
|
||||
HelpText = helpText,
|
||||
Type = type
|
||||
};
|
||||
}
|
||||
// The name of the HTML5 node. Should be used as the key for the posted data.
|
||||
public string Name;
|
||||
|
||||
public bool Constant;
|
||||
|
||||
// HTML5 compatible type string like "text", "textarea", "email", "password", etc.
|
||||
public string Type;
|
||||
|
||||
public static Field CreateFieldset()
|
||||
{
|
||||
return new Field { Type = "fieldset" };
|
||||
}
|
||||
|
||||
// The value field is what is currently in the DB or what the user entered, but possibly not saved yet due to validation errors.
|
||||
// If this is the first the user sees the form, then value and original value are the same. Value changes as the user starts interacting with the form.
|
||||
public string Value;
|
||||
|
||||
public bool Required;
|
||||
|
||||
// The translated label of the field.
|
||||
public string Label;
|
||||
|
||||
// The original value is the value that is currently saved in the backend. A "reset" button can be used to revert back to this. Should only be set from the constructor.
|
||||
public string OriginalValue;
|
||||
|
||||
// A useful note shown below the field or via a tooltip / info icon. Should be translated for the user.
|
||||
public string HelpText;
|
||||
|
||||
[JsonExtensionData] public IDictionary<string, JToken> AdditionalData { get; set; }
|
||||
public List<Field> Fields { get; set; } = new();
|
||||
|
||||
// The field is considered "valid" if there are no validation errors
|
||||
public List<string> ValidationErrors = new();
|
||||
|
||||
public virtual bool IsValid()
|
||||
{
|
||||
return ValidationErrors.Count == 0 && Fields.All(field => field.IsValid());
|
||||
}
|
||||
}
|
@ -1,110 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Form;
|
||||
|
||||
public class Form
|
||||
{
|
||||
#nullable enable
|
||||
public static Form Parse(string str)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(str);
|
||||
return JObject.Parse(str).ToObject<Form>(CamelCaseSerializerSettings.Serializer) ?? throw new InvalidOperationException("Impossible to deserialize Form");
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
return JObject.FromObject(this, CamelCaseSerializerSettings.Serializer).ToString(Newtonsoft.Json.Formatting.Indented);
|
||||
}
|
||||
#nullable restore
|
||||
|
||||
// Messages to be shown at the top of the form indicating user feedback like "Saved successfully" or "Please change X because of Y." or a warning, etc...
|
||||
public List<AlertMessage> TopMessages { get; set; } = new();
|
||||
|
||||
// Groups of fields in the form
|
||||
public List<Field> Fields { get; set; } = new();
|
||||
|
||||
// Are all the fields valid in the form?
|
||||
public bool IsValid()
|
||||
{
|
||||
if (TopMessages?.Any(t => t.Type == AlertMessage.AlertMessageType.Danger) is true)
|
||||
return false;
|
||||
return Fields.Select(f => f.IsValid()).All(o => o);
|
||||
}
|
||||
|
||||
public Field GetFieldByFullName(string fullName)
|
||||
{
|
||||
foreach (var f in GetAllFields())
|
||||
{
|
||||
if (f.FullName == fullName)
|
||||
return f.Field;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public IEnumerable<(string FullName, List<string> Path, Field Field)> GetAllFields()
|
||||
{
|
||||
HashSet<string> nameReturned = new();
|
||||
foreach (var f in GetAllFieldsCore(new List<string>(), Fields))
|
||||
{
|
||||
var fullName = string.Join('_', f.Path.Where(s => !string.IsNullOrEmpty(s)));
|
||||
if (!nameReturned.Add(fullName))
|
||||
continue;
|
||||
yield return (fullName, f.Path, f.Field);
|
||||
}
|
||||
}
|
||||
|
||||
public bool ValidateFieldNames(out List<string> errors)
|
||||
{
|
||||
errors = new List<string>();
|
||||
HashSet<string> nameReturned = new();
|
||||
foreach (var f in GetAllFieldsCore(new List<string>(), Fields))
|
||||
{
|
||||
var fullName = string.Join('_', f.Path.Where(s => !string.IsNullOrEmpty(s)));
|
||||
if (!nameReturned.Add(fullName))
|
||||
{
|
||||
errors.Add($"Form contains duplicate field names '{fullName}'");
|
||||
}
|
||||
}
|
||||
return errors.Count == 0;
|
||||
}
|
||||
|
||||
IEnumerable<(List<string> Path, Field Field)> GetAllFieldsCore(List<string> path, List<Field> fields)
|
||||
{
|
||||
foreach (var field in fields)
|
||||
{
|
||||
List<string> thisPath = new(path.Count + 1);
|
||||
thisPath.AddRange(path);
|
||||
if (!string.IsNullOrEmpty(field.Name))
|
||||
{
|
||||
thisPath.Add(field.Name);
|
||||
yield return (thisPath, field);
|
||||
}
|
||||
foreach (var descendant in GetAllFieldsCore(thisPath, field.Fields))
|
||||
{
|
||||
descendant.Field.Constant = field.Constant || descendant.Field.Constant;
|
||||
yield return descendant;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplyValuesFromForm(IEnumerable<KeyValuePair<string, StringValues>> form)
|
||||
{
|
||||
var values = form.GroupBy(f => f.Key, f => f.Value).ToDictionary(g => g.Key, g => g.First());
|
||||
foreach (var f in GetAllFields())
|
||||
{
|
||||
if (f.Field.Constant || !values.TryGetValue(f.FullName, out var val))
|
||||
continue;
|
||||
|
||||
f.Field.Value = val;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@ -1,60 +1,27 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using BTCPayServer.Abstractions.Contracts;
|
||||
using BTCPayServer.Contracts;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Models
|
||||
namespace BTCPayServer.Models
|
||||
{
|
||||
public abstract class BaseBTCPayServerPlugin : IBTCPayServerPlugin
|
||||
{
|
||||
public virtual string Identifier
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetType().GetTypeInfo().Assembly.GetName().Name;
|
||||
}
|
||||
}
|
||||
public virtual string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetType().GetTypeInfo().Assembly
|
||||
.GetCustomAttribute<AssemblyProductAttribute>()?
|
||||
.Product ?? "???";
|
||||
}
|
||||
}
|
||||
public abstract string Identifier { get; }
|
||||
public abstract string Name { get; }
|
||||
|
||||
public virtual Version Version
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetVersion(GetType().GetTypeInfo().Assembly
|
||||
.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?
|
||||
.InformationalVersion) ??
|
||||
Assembly.GetAssembly(GetType())?.GetName()?.Version ??
|
||||
new Version(1, 0, 0, 0);
|
||||
return Assembly.GetAssembly(GetType())?.GetName().Version ?? new Version(1, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private static Version GetVersion(string informationalVersion)
|
||||
{
|
||||
if (informationalVersion is null)
|
||||
return null;
|
||||
Version.TryParse(informationalVersion, out var r);
|
||||
return r;
|
||||
}
|
||||
|
||||
public virtual string Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetType().GetTypeInfo().Assembly
|
||||
.GetCustomAttribute<AssemblyDescriptionAttribute>()?
|
||||
.Description ?? string.Empty;
|
||||
}
|
||||
}
|
||||
public abstract string Description { get; }
|
||||
public bool SystemPlugin { get; set; }
|
||||
public bool SystemExtension { get; set; }
|
||||
public virtual IBTCPayServerPlugin.PluginDependency[] Dependencies { get; } = Array.Empty<IBTCPayServerPlugin.PluginDependency>();
|
||||
|
||||
public virtual void Execute(IApplicationBuilder applicationBuilder,
|
||||
|
@ -1,34 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Models
|
||||
{
|
||||
public class ConfirmModel
|
||||
{
|
||||
private const string ButtonClassDefault = "btn-danger";
|
||||
|
||||
public ConfirmModel() { }
|
||||
|
||||
public ConfirmModel(string title, string desc, string action = null, string buttonClass = ButtonClassDefault, string actionName = null, string controllerName = null)
|
||||
{
|
||||
Title = title;
|
||||
Description = desc;
|
||||
Action = action;
|
||||
ActionName = actionName;
|
||||
ControllerName = controllerName;
|
||||
ButtonClass = buttonClass;
|
||||
|
||||
if (Description.Contains("<strong>", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
DescriptionHtml = true;
|
||||
}
|
||||
}
|
||||
|
||||
public string Title { get; set; }
|
||||
public string Description { get; set; }
|
||||
public bool DescriptionHtml { get; set; }
|
||||
public string Action { get; set; }
|
||||
public string ActionName { get; set; }
|
||||
public string ControllerName { get; set; }
|
||||
public string ButtonClass { get; set; } = ButtonClassDefault;
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
namespace BTCPayServer.Abstractions.Models
|
||||
{
|
||||
public class DatabaseOptions
|
||||
{
|
||||
public string ConnectionString { get; set; }
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Models
|
||||
namespace BTCPayServer.Models
|
||||
{
|
||||
public class StatusMessageModel
|
||||
{
|
||||
@ -14,6 +14,14 @@ namespace BTCPayServer.Abstractions.Models
|
||||
|
||||
public string SeverityCSS => ToString(Severity);
|
||||
|
||||
private void ParseNonJsonStatus(string s)
|
||||
{
|
||||
Message = s;
|
||||
Severity = s.StartsWith("Error", StringComparison.InvariantCultureIgnoreCase)
|
||||
? StatusSeverity.Error
|
||||
: StatusSeverity.Success;
|
||||
}
|
||||
|
||||
public static string ToString(StatusSeverity severity)
|
||||
{
|
||||
switch (severity)
|
||||
|
@ -1,16 +0,0 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Abstractions.Contracts;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Models;
|
||||
|
||||
public class UploadImageResultModel
|
||||
{
|
||||
public bool Success { get; set; }
|
||||
public string Response { get; set; } = string.Empty;
|
||||
public IStoredFile? StoredFile { get; set; }
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace BTCPayServer.Security;
|
||||
|
||||
public class AuthorizationFilterHandle
|
||||
{
|
||||
public AuthorizationHandlerContext Context { get; }
|
||||
public PolicyRequirement Requirement { get; }
|
||||
public HttpContext HttpContext { get; }
|
||||
public bool Success { get; private set; }
|
||||
|
||||
public AuthorizationFilterHandle(
|
||||
AuthorizationHandlerContext context,
|
||||
PolicyRequirement requirement,
|
||||
HttpContext httpContext)
|
||||
{
|
||||
Context = context;
|
||||
Requirement = requirement;
|
||||
HttpContext = httpContext;
|
||||
}
|
||||
|
||||
public void MarkSuccessful()
|
||||
{
|
||||
Success = true;
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Abstractions.Contracts;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Services
|
||||
{
|
||||
public abstract class PluginAction<T> : IPluginHookAction
|
||||
{
|
||||
public abstract string Hook { get; }
|
||||
public Task Execute(object args)
|
||||
{
|
||||
return Execute(args is T args1 ? args1 : default);
|
||||
}
|
||||
|
||||
public abstract Task Execute(T arg);
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Abstractions.Contracts;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Services
|
||||
{
|
||||
public abstract class PluginHookFilter<T> : IPluginHookFilter
|
||||
{
|
||||
public abstract string Hook { get; }
|
||||
|
||||
public Task<object> Execute(object args)
|
||||
{
|
||||
return Execute(args is T args1 ? args1 : default).ContinueWith(task => task.Result as object);
|
||||
}
|
||||
|
||||
public abstract Task<T> Execute(T arg);
|
||||
}
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
using System.Web;
|
||||
using Ganss.Xss;
|
||||
using Microsoft.AspNetCore.Html;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Services
|
||||
{
|
||||
public class Safe
|
||||
{
|
||||
private readonly IHtmlHelper _htmlHelper;
|
||||
private readonly IJsonHelper _jsonHelper;
|
||||
private readonly HtmlSanitizer _htmlSanitizer;
|
||||
|
||||
public Safe(IHtmlHelper htmlHelper, IJsonHelper jsonHelper, HtmlSanitizer htmlSanitizer)
|
||||
{
|
||||
_htmlHelper = htmlHelper;
|
||||
_jsonHelper = jsonHelper;
|
||||
_htmlSanitizer = htmlSanitizer;
|
||||
|
||||
|
||||
}
|
||||
|
||||
public IHtmlContent Raw(string value)
|
||||
{
|
||||
return _htmlHelper.Raw(_htmlSanitizer.Sanitize(value));
|
||||
}
|
||||
|
||||
public IHtmlContent RawEncode(string value)
|
||||
{
|
||||
return _htmlHelper.Raw(HttpUtility.HtmlEncode(_htmlSanitizer.Sanitize(value)));
|
||||
}
|
||||
|
||||
public IHtmlContent Json(object model)
|
||||
{
|
||||
return _htmlHelper.Raw(_jsonHelper.Serialize(model));
|
||||
}
|
||||
|
||||
public IHtmlContent Meta(string inputHtml) => _htmlHelper.Raw(RawMeta(inputHtml, out _));
|
||||
|
||||
public string RawMeta(string inputHtml, out bool isHtmlModified)
|
||||
{
|
||||
bool bHtmlModified;
|
||||
HtmlSanitizer sane = new HtmlSanitizer();
|
||||
|
||||
sane.AllowedTags.Clear();
|
||||
sane.AllowedTags.Add("meta");
|
||||
|
||||
sane.AllowedAttributes.Clear();
|
||||
sane.AllowedAttributes.Add("name");
|
||||
sane.AllowedAttributes.Add("http-equiv");
|
||||
sane.AllowedAttributes.Add("content");
|
||||
sane.AllowedAttributes.Add("value");
|
||||
sane.AllowedAttributes.Add("property");
|
||||
|
||||
sane.AllowDataAttributes = false;
|
||||
|
||||
sane.RemovingTag += (sender, e) => bHtmlModified = true;
|
||||
sane.RemovingAtRule += (sender, e) => bHtmlModified = true;
|
||||
sane.RemovingAttribute += (sender, e) => bHtmlModified = true;
|
||||
sane.RemovingComment += (sender, e) => bHtmlModified = true;
|
||||
sane.RemovingCssClass += (sender, e) => bHtmlModified = true;
|
||||
sane.RemovingStyle += (sender, e) => bHtmlModified = true;
|
||||
|
||||
bHtmlModified = false;
|
||||
|
||||
var sRet = sane.Sanitize(inputHtml);
|
||||
isHtmlModified = bHtmlModified;
|
||||
|
||||
return sRet;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
using System;
|
||||
using BTCPayServer.Abstractions.Contracts;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Services
|
||||
{
|
||||
public class UIExtension : IUIExtension
|
||||
{
|
||||
[Obsolete("Use extension method BTCPayServer.Extensions.AddUIExtension(this IServiceCollection services, string location, string partialViewName) instead")]
|
||||
public UIExtension(string partial, string location)
|
||||
{
|
||||
Partial = partial;
|
||||
Location = location;
|
||||
}
|
||||
|
||||
public string Partial { get; }
|
||||
public string Location { get; }
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
using System;
|
||||
using BTCPayServer.Security;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
|
||||
namespace BTCPayServer.Abstractions.TagHelpers;
|
||||
|
||||
/// <summary>
|
||||
/// Add sha256- to allow inline event handlers in a:href=javascript:
|
||||
/// </summary>
|
||||
[HtmlTargetElement("a", Attributes = "csp-allow")]
|
||||
public class CSPA : TagHelper
|
||||
{
|
||||
private readonly ContentSecurityPolicies _csp;
|
||||
public CSPA(ContentSecurityPolicies csp)
|
||||
{
|
||||
_csp = csp;
|
||||
}
|
||||
public override void Process(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
output.Attributes.RemoveAll("csp-allow");
|
||||
if (output.Attributes.TryGetAttribute("href", out var attr))
|
||||
{
|
||||
var v = attr.Value.ToString();
|
||||
if (v.StartsWith("javascript:", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
_csp.AllowUnsafeHashes(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BTCPayServer.Security;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
|
||||
namespace BTCPayServer.Abstractions.TagHelpers;
|
||||
|
||||
/// <summary>
|
||||
/// Add 'unsafe-hashes' and sha256- to allow inline event handlers in CSP
|
||||
/// </summary>
|
||||
[HtmlTargetElement(Attributes = "onclick")]
|
||||
[HtmlTargetElement(Attributes = "onkeypress")]
|
||||
[HtmlTargetElement(Attributes = "onchange")]
|
||||
[HtmlTargetElement(Attributes = "onsubmit")]
|
||||
public class CSPEventTagHelper : TagHelper
|
||||
{
|
||||
public const string EventNames = "onclick,onkeypress,onchange,onsubmit";
|
||||
private readonly ContentSecurityPolicies _csp;
|
||||
|
||||
readonly static HashSet<string> EventSet = EventNames.Split(',')
|
||||
.ToHashSet();
|
||||
public CSPEventTagHelper(ContentSecurityPolicies csp)
|
||||
{
|
||||
_csp = csp;
|
||||
}
|
||||
public override void Process(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
foreach (var attr in output.Attributes)
|
||||
{
|
||||
var n = attr.Name.ToLowerInvariant();
|
||||
if (EventSet.Contains(n))
|
||||
{
|
||||
_csp.AllowUnsafeHashes(attr.Value.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
using BTCPayServer.Security;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
using NBitcoin;
|
||||
|
||||
namespace BTCPayServer.Abstractions.TagHelpers;
|
||||
|
||||
/// <summary>
|
||||
/// Add a nonce-* so the inline-script can pass CSP rule when they are rendered server-side
|
||||
/// </summary>
|
||||
[HtmlTargetElement("script")]
|
||||
public class CSPInlineScriptTagHelper : TagHelper
|
||||
{
|
||||
private readonly ContentSecurityPolicies _csp;
|
||||
|
||||
public CSPInlineScriptTagHelper(ContentSecurityPolicies csp)
|
||||
{
|
||||
_csp = csp;
|
||||
}
|
||||
|
||||
public override void Process(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
if (output.Attributes.ContainsName("src"))
|
||||
return;
|
||||
if (output.Attributes.TryGetAttribute("type", out var attr))
|
||||
{
|
||||
if (attr.Value?.ToString() != "text/javascript")
|
||||
return;
|
||||
}
|
||||
var nonce = RandomUtils.GetUInt256().ToString().Substring(0, 32);
|
||||
output.Attributes.Add(new TagHelperAttribute("nonce", nonce));
|
||||
_csp.Add("script-src", $"'nonce-{nonce}'");
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Security;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
|
||||
namespace BTCPayServer.Abstractions.TagHelpers;
|
||||
|
||||
/// <summary>
|
||||
/// Add sha256- to allow inline event handlers in CSP
|
||||
/// </summary>
|
||||
[HtmlTargetElement("template", Attributes = "csp-allow")]
|
||||
public class CSPTemplate : TagHelper
|
||||
{
|
||||
private readonly ContentSecurityPolicies _csp;
|
||||
public CSPTemplate(ContentSecurityPolicies csp)
|
||||
{
|
||||
_csp = csp;
|
||||
}
|
||||
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
output.Attributes.RemoveAll("csp-allow");
|
||||
var childContent = await output.GetChildContentAsync();
|
||||
var content = childContent.GetContent();
|
||||
_csp.AllowInline(content);
|
||||
}
|
||||
}
|
@ -1,94 +0,0 @@
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace BTCPayServer.Abstractions.TagHelpers;
|
||||
|
||||
[HtmlTargetElement(Attributes = "[permission]")]
|
||||
[HtmlTargetElement(Attributes = "[not-permission]")]
|
||||
public class PermissionTagHelper : TagHelper
|
||||
{
|
||||
private readonly IAuthorizationService _authorizationService;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
|
||||
public PermissionTagHelper(IAuthorizationService authorizationService, IHttpContextAccessor httpContextAccessor)
|
||||
{
|
||||
_authorizationService = authorizationService;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
public string Permission { get; set; }
|
||||
public string NotPermission { get; set; }
|
||||
public string PermissionResource { get; set; }
|
||||
public bool AndMode { get; set; } = false;
|
||||
|
||||
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
var permissions = Permission?.Split(',', StringSplitOptions.RemoveEmptyEntries) ?? Array.Empty<string>();
|
||||
var notPermissions = NotPermission?.Split(',', StringSplitOptions.RemoveEmptyEntries) ?? Array.Empty<string>();
|
||||
|
||||
if (!permissions.Any() && !notPermissions.Any())
|
||||
return;
|
||||
if (_httpContextAccessor.HttpContext is null)
|
||||
return;
|
||||
|
||||
bool shouldRender = true; // Assume tag should be rendered unless a check fails
|
||||
|
||||
// Process 'Permission' - User must have these permissions
|
||||
if (permissions.Any())
|
||||
{
|
||||
bool finalResult = AndMode;
|
||||
foreach (var perm in permissions)
|
||||
{
|
||||
var key = $"{perm}_{PermissionResource}";
|
||||
AuthorizationResult res = await GetOrAddAuthorizationResult(key, perm);
|
||||
|
||||
if (AndMode)
|
||||
finalResult &= res.Succeeded;
|
||||
else
|
||||
finalResult |= res.Succeeded;
|
||||
|
||||
if (!AndMode && finalResult) break;
|
||||
}
|
||||
|
||||
shouldRender = finalResult;
|
||||
}
|
||||
|
||||
// Process 'NotPermission' - User must not have these permissions
|
||||
if (shouldRender && notPermissions.Any())
|
||||
{
|
||||
foreach (var notPerm in notPermissions)
|
||||
{
|
||||
var key = $"{notPerm}_{PermissionResource}";
|
||||
AuthorizationResult res = await GetOrAddAuthorizationResult(key, notPerm);
|
||||
|
||||
if (res.Succeeded) // If the user has a 'NotPermission', they should not see the tag
|
||||
{
|
||||
shouldRender = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!shouldRender)
|
||||
{
|
||||
output.SuppressOutput();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<AuthorizationResult> GetOrAddAuthorizationResult(string key, string permission)
|
||||
{
|
||||
if (!_httpContextAccessor.HttpContext.Items.TryGetValue(key, out var cachedResult))
|
||||
{
|
||||
var res = await _authorizationService.AuthorizeAsync(_httpContextAccessor.HttpContext.User,
|
||||
PermissionResource, permission);
|
||||
_httpContextAccessor.HttpContext.Items[key] = res;
|
||||
return res;
|
||||
}
|
||||
|
||||
return cachedResult as AuthorizationResult;
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
|
||||
namespace BTCPayServer.Abstractions.TagHelpers;
|
||||
|
||||
[HtmlTargetElement("form", Attributes = "[permissioned]")]
|
||||
public partial class PermissionedFormTagHelper(
|
||||
IAuthorizationService authorizationService,
|
||||
IHttpContextAccessor httpContextAccessor)
|
||||
: TagHelper
|
||||
{
|
||||
public string Permissioned { get; set; }
|
||||
public string PermissionResource { get; set; }
|
||||
|
||||
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
if (httpContextAccessor.HttpContext is null || string.IsNullOrEmpty(Permissioned))
|
||||
return;
|
||||
|
||||
var res = await authorizationService.AuthorizeAsync(httpContextAccessor.HttpContext.User,
|
||||
PermissionResource, Permissioned);
|
||||
if (!res.Succeeded)
|
||||
{
|
||||
var content = await output.GetChildContentAsync();
|
||||
var html = SubmitButtonRegex().Replace(content.GetContent(), "");
|
||||
output.Content.SetHtmlContent($"<fieldset disabled>{html}</fieldset>");
|
||||
}
|
||||
}
|
||||
|
||||
[GeneratedRegex("<(button|input).*?type=\"submit\".*?>.*?</\\1>")]
|
||||
private static partial Regex SubmitButtonRegex();
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Text.Encodings.Web;
|
||||
using Microsoft.AspNetCore.Html;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.TagHelpers;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.AspNetCore.Mvc.Routing;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
|
||||
namespace BTCPayServer.Abstractions.TagHelpers;
|
||||
|
||||
// Make sure that <svg><use href=/ are correctly working if rootpath is present
|
||||
[HtmlTargetElement("use", Attributes = "href")]
|
||||
public class SVGUse : UrlResolutionTagHelper2
|
||||
{
|
||||
private readonly IFileVersionProvider _fileVersionProvider;
|
||||
|
||||
public SVGUse(IUrlHelperFactory urlHelperFactory, HtmlEncoder htmlEncoder, IFileVersionProvider fileVersionProvider) : base(urlHelperFactory, htmlEncoder)
|
||||
{
|
||||
_fileVersionProvider = fileVersionProvider;
|
||||
}
|
||||
|
||||
public override void Process(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
var attr = output.Attributes["href"].Value.ToString();
|
||||
var symbolIndex = attr!.IndexOf("#", StringComparison.InvariantCulture);
|
||||
var start = attr.IndexOf("~", StringComparison.InvariantCulture) + 1;
|
||||
var length = (symbolIndex != -1 ? symbolIndex : attr.Length) - start;
|
||||
var filePath = attr.Substring(start, length);
|
||||
if (!string.IsNullOrEmpty(filePath))
|
||||
{
|
||||
var versioned = _fileVersionProvider.AddFileVersionToPath(ViewContext.HttpContext.Request.PathBase, filePath);
|
||||
attr = attr.Replace(filePath, versioned);
|
||||
}
|
||||
output.Attributes.SetAttribute("href", attr);
|
||||
base.Process(context, output);
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
using BTCPayServer.Abstractions.Services;
|
||||
using BTCPayServer.Security;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
using NBitcoin;
|
||||
|
||||
namespace BTCPayServer.Abstractions.TagHelpers;
|
||||
|
||||
[HtmlTargetElement("srv-model")]
|
||||
public class SrvModel : TagHelper
|
||||
{
|
||||
private readonly Safe _safe;
|
||||
private readonly ContentSecurityPolicies _csp;
|
||||
|
||||
public SrvModel(Safe safe, ContentSecurityPolicies csp)
|
||||
{
|
||||
_safe = safe;
|
||||
_csp = csp;
|
||||
}
|
||||
public string VarName { get; set; } = "srvModel";
|
||||
public object Model { get; set; }
|
||||
public override void Process(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
output.TagName = "script";
|
||||
output.TagMode = TagMode.StartTagAndEndTag;
|
||||
output.Attributes.Add(new TagHelperAttribute("type", "text/javascript"));
|
||||
var nonce = RandomUtils.GetUInt256().ToString().Substring(0, 32);
|
||||
output.Attributes.Add(new TagHelperAttribute("nonce", nonce));
|
||||
_csp.Add("script-src", $"'nonce-{nonce}'");
|
||||
output.Content.SetHtmlContent($"var {VarName} = {_safe.Json(Model)};");
|
||||
}
|
||||
}
|
@ -1,314 +0,0 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Text.Encodings.Web;
|
||||
using Microsoft.AspNetCore.Html;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.TagHelpers;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.AspNetCore.Mvc.Routing;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
|
||||
|
||||
namespace BTCPayServer.Abstractions.TagHelpers
|
||||
{
|
||||
// A copy of https://github.com/dotnet/aspnetcore/blob/39f0e0b8f40b4754418f81aef0de58a9204a1fe5/src/Mvc/Mvc.Razor/src/TagHelpers/UrlResolutionTagHelper.cs
|
||||
// slightly modified to also work on use tag.
|
||||
public class UrlResolutionTagHelper2 : TagHelper
|
||||
{
|
||||
// Valid whitespace characters defined by the HTML5 spec.
|
||||
private static readonly char[] ValidAttributeWhitespaceChars =
|
||||
new[] { '\t', '\n', '\u000C', '\r', ' ' };
|
||||
private static readonly Dictionary<string, string[]> ElementAttributeLookups =
|
||||
new(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{ "use", new[] { "href" } },
|
||||
{ "a", new[] { "href" } },
|
||||
{ "applet", new[] { "archive" } },
|
||||
{ "area", new[] { "href" } },
|
||||
{ "audio", new[] { "src" } },
|
||||
{ "base", new[] { "href" } },
|
||||
{ "blockquote", new[] { "cite" } },
|
||||
{ "button", new[] { "formaction" } },
|
||||
{ "del", new[] { "cite" } },
|
||||
{ "embed", new[] { "src" } },
|
||||
{ "form", new[] { "action" } },
|
||||
{ "html", new[] { "manifest" } },
|
||||
{ "iframe", new[] { "src" } },
|
||||
{ "img", new[] { "src", "srcset" } },
|
||||
{ "input", new[] { "src", "formaction" } },
|
||||
{ "ins", new[] { "cite" } },
|
||||
{ "link", new[] { "href" } },
|
||||
{ "menuitem", new[] { "icon" } },
|
||||
{ "object", new[] { "archive", "data" } },
|
||||
{ "q", new[] { "cite" } },
|
||||
{ "script", new[] { "src" } },
|
||||
{ "source", new[] { "src", "srcset" } },
|
||||
{ "track", new[] { "src" } },
|
||||
{ "video", new[] { "poster", "src" } },
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="UrlResolutionTagHelper"/>.
|
||||
/// </summary>
|
||||
/// <param name="urlHelperFactory">The <see cref="IUrlHelperFactory"/>.</param>
|
||||
/// <param name="htmlEncoder">The <see cref="HtmlEncoder"/>.</param>
|
||||
public UrlResolutionTagHelper2(IUrlHelperFactory urlHelperFactory, HtmlEncoder htmlEncoder)
|
||||
{
|
||||
UrlHelperFactory = urlHelperFactory;
|
||||
HtmlEncoder = htmlEncoder;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int Order => -1000 - 999;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IUrlHelperFactory"/>.
|
||||
/// </summary>
|
||||
protected IUrlHelperFactory UrlHelperFactory { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="HtmlEncoder"/>.
|
||||
/// </summary>
|
||||
protected HtmlEncoder HtmlEncoder { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ViewContext"/>.
|
||||
/// </summary>
|
||||
[HtmlAttributeNotBound]
|
||||
[ViewContext]
|
||||
public ViewContext ViewContext { get; set; } = default!;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Process(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(context);
|
||||
ArgumentNullException.ThrowIfNull(output);
|
||||
|
||||
if (output.TagName == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ElementAttributeLookups.TryGetValue(output.TagName, out var attributeNames))
|
||||
{
|
||||
for (var i = 0; i < attributeNames.Length; i++)
|
||||
{
|
||||
ProcessUrlAttribute(attributeNames[i], output);
|
||||
}
|
||||
}
|
||||
|
||||
// itemid can be present on any HTML element.
|
||||
ProcessUrlAttribute("itemid", output);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves and updates URL values starting with '~/' (relative to the application's 'webroot' setting) for
|
||||
/// <paramref name="output"/>'s <see cref="TagHelperOutput.Attributes"/> whose
|
||||
/// <see cref="TagHelperAttribute.Name"/> is <paramref name="attributeName"/>.
|
||||
/// </summary>
|
||||
/// <param name="attributeName">The attribute name used to lookup values to resolve.</param>
|
||||
/// <param name="output">The <see cref="TagHelperOutput"/>.</param>
|
||||
protected void ProcessUrlAttribute(string attributeName, TagHelperOutput output)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(attributeName);
|
||||
ArgumentNullException.ThrowIfNull(output);
|
||||
|
||||
var attributes = output.Attributes;
|
||||
// Read interface .Count once rather than per iteration
|
||||
var attributesCount = attributes.Count;
|
||||
for (var i = 0; i < attributesCount; i++)
|
||||
{
|
||||
var attribute = attributes[i];
|
||||
if (!string.Equals(attribute.Name, attributeName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (attribute.Value is string stringValue)
|
||||
{
|
||||
if (TryResolveUrl(stringValue, resolvedUrl: out string? resolvedUrl))
|
||||
{
|
||||
attributes[i] = new TagHelperAttribute(
|
||||
attribute.Name,
|
||||
resolvedUrl,
|
||||
attribute.ValueStyle);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (attribute.Value is IHtmlContent htmlContent)
|
||||
{
|
||||
var htmlString = htmlContent as HtmlString;
|
||||
if (htmlString != null)
|
||||
{
|
||||
// No need for a StringWriter in this case.
|
||||
stringValue = htmlString.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
using var writer = new StringWriter();
|
||||
htmlContent.WriteTo(writer, HtmlEncoder);
|
||||
stringValue = writer.ToString();
|
||||
}
|
||||
|
||||
if (TryResolveUrl(stringValue, resolvedUrl: out IHtmlContent? resolvedUrl))
|
||||
{
|
||||
attributes[i] = new TagHelperAttribute(
|
||||
attribute.Name,
|
||||
resolvedUrl,
|
||||
attribute.ValueStyle);
|
||||
}
|
||||
else if (htmlString == null)
|
||||
{
|
||||
// Not a ~/ URL. Just avoid re-encoding the attribute value later.
|
||||
attributes[i] = new TagHelperAttribute(
|
||||
attribute.Name,
|
||||
new HtmlString(stringValue),
|
||||
attribute.ValueStyle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to resolve the given <paramref name="url"/> value relative to the application's 'webroot' setting.
|
||||
/// </summary>
|
||||
/// <param name="url">The URL to resolve.</param>
|
||||
/// <param name="resolvedUrl">Absolute URL beginning with the application's virtual root. <c>null</c> if
|
||||
/// <paramref name="url"/> could not be resolved.</param>
|
||||
/// <returns><c>true</c> if the <paramref name="url"/> could be resolved; <c>false</c> otherwise.</returns>
|
||||
protected bool TryResolveUrl(string url, out string? resolvedUrl)
|
||||
{
|
||||
resolvedUrl = null;
|
||||
var start = FindRelativeStart(url);
|
||||
if (start == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var trimmedUrl = CreateTrimmedString(url, start);
|
||||
|
||||
var urlHelper = UrlHelperFactory.GetUrlHelper(ViewContext);
|
||||
resolvedUrl = urlHelper.Content(trimmedUrl);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to resolve the given <paramref name="url"/> value relative to the application's 'webroot' setting.
|
||||
/// </summary>
|
||||
/// <param name="url">The URL to resolve.</param>
|
||||
/// <param name="resolvedUrl">
|
||||
/// Absolute URL beginning with the application's virtual root. <c>null</c> if <paramref name="url"/> could
|
||||
/// not be resolved.
|
||||
/// </param>
|
||||
/// <returns><c>true</c> if the <paramref name="url"/> could be resolved; <c>false</c> otherwise.</returns>
|
||||
protected bool TryResolveUrl(string url, [NotNullWhen(true)] out IHtmlContent? resolvedUrl)
|
||||
{
|
||||
resolvedUrl = null;
|
||||
var start = FindRelativeStart(url);
|
||||
if (start == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var trimmedUrl = CreateTrimmedString(url, start);
|
||||
|
||||
var urlHelper = UrlHelperFactory.GetUrlHelper(ViewContext);
|
||||
var appRelativeUrl = urlHelper.Content(trimmedUrl);
|
||||
var postTildeSlashUrlValue = trimmedUrl.Substring(2);
|
||||
|
||||
if (!appRelativeUrl.EndsWith(postTildeSlashUrlValue, StringComparison.Ordinal))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
resolvedUrl = new EncodeFirstSegmentContent(
|
||||
appRelativeUrl,
|
||||
appRelativeUrl.Length - postTildeSlashUrlValue.Length,
|
||||
postTildeSlashUrlValue);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static int FindRelativeStart(string url)
|
||||
{
|
||||
if (url == null || url.Length < 2)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
var maxTestLength = url.Length - 2;
|
||||
|
||||
var start = 0;
|
||||
for (; start < url.Length; start++)
|
||||
{
|
||||
if (start > maxTestLength)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!IsCharWhitespace(url[start]))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Before doing more work, ensure that the URL we're looking at is app-relative.
|
||||
if (url[start] != '~' || url[start + 1] != '/')
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
private static string CreateTrimmedString(string input, int start)
|
||||
{
|
||||
var end = input.Length - 1;
|
||||
for (; end >= start; end--)
|
||||
{
|
||||
if (!IsCharWhitespace(input[end]))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var len = end - start + 1;
|
||||
|
||||
// Substring returns same string if start == 0 && len == Length
|
||||
return input.Substring(start, len);
|
||||
}
|
||||
|
||||
private static bool IsCharWhitespace(char ch)
|
||||
{
|
||||
return ValidAttributeWhitespaceChars.AsSpan().IndexOf(ch) != -1;
|
||||
}
|
||||
|
||||
private sealed class EncodeFirstSegmentContent : IHtmlContent
|
||||
{
|
||||
private readonly string _firstSegment;
|
||||
private readonly int _firstSegmentLength;
|
||||
private readonly string _secondSegment;
|
||||
|
||||
public EncodeFirstSegmentContent(string firstSegment, int firstSegmentLength, string secondSegment)
|
||||
{
|
||||
_firstSegment = firstSegment;
|
||||
_firstSegmentLength = firstSegmentLength;
|
||||
_secondSegment = secondSegment;
|
||||
}
|
||||
|
||||
public void WriteTo(TextWriter writer, HtmlEncoder encoder)
|
||||
{
|
||||
encoder.Encode(writer, _firstSegment, 0, _firstSegmentLength);
|
||||
writer.Write(_secondSegment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -2,7 +2,6 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<LangVersion>10.0</LangVersion>
|
||||
<Company>BTCPay Server</Company>
|
||||
<Copyright>Copyright © BTCPay Server 2020</Copyright>
|
||||
<Description>A client library for BTCPay Server Greenfield API</Description>
|
||||
@ -12,11 +11,9 @@
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<RepositoryUrl>https://github.com/btcpayserver/btcpayserver</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
<Platforms>AnyCPU</Platforms>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<Version Condition=" '$(Version)' == '' ">2.0.1</Version>
|
||||
<Version Condition=" '$(Version)' == '' ">1.1.1</Version>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
@ -30,9 +27,9 @@
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BTCPayServer.Lightning.Common" Version="1.5.2" />
|
||||
<PackageReference Include="NBitcoin" Version="7.0.48" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="NBitcoin" Version="5.0.60" />
|
||||
<PackageReference Include="BTCPayServer.Lightning.Common" Version="1.2.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="icon.png" Pack="true" PackagePath="\" />
|
||||
|
@ -4,41 +4,36 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
|
||||
namespace BTCPayServer.Client;
|
||||
|
||||
public partial class BTCPayServerClient
|
||||
namespace BTCPayServer.Client
|
||||
{
|
||||
public virtual async Task<ApiKeyData> GetCurrentAPIKeyInfo(CancellationToken token = default)
|
||||
public partial class BTCPayServerClient
|
||||
{
|
||||
return await SendHttpRequest<ApiKeyData>("api/v1/api-keys/current", null, HttpMethod.Get, token);
|
||||
}
|
||||
public virtual async Task<ApiKeyData> GetCurrentAPIKeyInfo(CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest("api/v1/api-keys/current"), token);
|
||||
return await HandleResponse<ApiKeyData>(response);
|
||||
}
|
||||
|
||||
public virtual async Task<ApiKeyData> CreateAPIKey(CreateApiKeyRequest request, CancellationToken token = default)
|
||||
{
|
||||
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||
return await SendHttpRequest<ApiKeyData>("api/v1/api-keys", request, HttpMethod.Post, token);
|
||||
}
|
||||
public virtual async Task<ApiKeyData> CreateAPIKey(CreateApiKeyRequest request, CancellationToken token = default)
|
||||
{
|
||||
if (request == null)
|
||||
throw new ArgumentNullException(nameof(request));
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest("api/v1/api-keys", bodyPayload: request, method: HttpMethod.Post), token);
|
||||
return await HandleResponse<ApiKeyData>(response);
|
||||
}
|
||||
|
||||
public virtual async Task<ApiKeyData> CreateAPIKey(string userId, CreateApiKeyRequest request, CancellationToken token = default)
|
||||
{
|
||||
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||
return await SendHttpRequest<ApiKeyData>($"api/v1/users/{userId}/api-keys", request, HttpMethod.Post, token);
|
||||
}
|
||||
public virtual async Task RevokeCurrentAPIKeyInfo(CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest("api/v1/api-keys/current", null, HttpMethod.Delete), token);
|
||||
await HandleResponse(response);
|
||||
}
|
||||
|
||||
public virtual async Task RevokeCurrentAPIKeyInfo(CancellationToken token = default)
|
||||
{
|
||||
await SendHttpRequest("api/v1/api-keys/current", null, HttpMethod.Delete, token);
|
||||
}
|
||||
|
||||
public virtual async Task RevokeAPIKey(string apikey, CancellationToken token = default)
|
||||
{
|
||||
if (apikey == null) throw new ArgumentNullException(nameof(apikey));
|
||||
await SendHttpRequest($"api/v1/api-keys/{apikey}", null, HttpMethod.Delete, token);
|
||||
}
|
||||
public virtual async Task RevokeAPIKey(string userId, string apikey, CancellationToken token = default)
|
||||
{
|
||||
if (apikey == null) throw new ArgumentNullException(nameof(apikey));
|
||||
if (userId is null) throw new ArgumentNullException(nameof(userId));
|
||||
await SendHttpRequest($"api/v1/users/{userId}/api-keys/{apikey}", null, HttpMethod.Delete, token);
|
||||
public virtual async Task RevokeAPIKey(string apikey, CancellationToken token = default)
|
||||
{
|
||||
if (apikey == null)
|
||||
throw new ArgumentNullException(nameof(apikey));
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/api-keys/{apikey}", null, HttpMethod.Delete), token);
|
||||
await HandleResponse(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,91 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
|
||||
namespace BTCPayServer.Client;
|
||||
|
||||
public partial class BTCPayServerClient
|
||||
{
|
||||
public virtual async Task<PointOfSaleAppData> CreatePointOfSaleApp(string storeId,
|
||||
PointOfSaleAppRequest request, CancellationToken token = default)
|
||||
{
|
||||
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||
return await SendHttpRequest<PointOfSaleAppData>($"api/v1/stores/{storeId}/apps/pos", request, HttpMethod.Post, token);
|
||||
}
|
||||
|
||||
public virtual async Task<CrowdfundAppData> CreateCrowdfundApp(string storeId,
|
||||
CrowdfundAppRequest request, CancellationToken token = default)
|
||||
{
|
||||
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||
return await SendHttpRequest<CrowdfundAppData>($"api/v1/stores/{storeId}/apps/crowdfund", request, HttpMethod.Post, token);
|
||||
}
|
||||
|
||||
public virtual async Task<PointOfSaleAppData> UpdatePointOfSaleApp(string appId,
|
||||
PointOfSaleAppRequest request, CancellationToken token = default)
|
||||
{
|
||||
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||
return await SendHttpRequest<PointOfSaleAppData>($"api/v1/apps/pos/{appId}", request, HttpMethod.Put, token);
|
||||
}
|
||||
|
||||
public virtual async Task<AppBaseData> GetApp(string appId, CancellationToken token = default)
|
||||
{
|
||||
if (appId == null) throw new ArgumentNullException(nameof(appId));
|
||||
return await SendHttpRequest<AppBaseData>($"api/v1/apps/{appId}", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<AppBaseData[]> GetAllApps(string storeId, CancellationToken token = default)
|
||||
{
|
||||
if (storeId == null) throw new ArgumentNullException(nameof(storeId));
|
||||
return await SendHttpRequest<AppBaseData[]>($"api/v1/stores/{storeId}/apps", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<AppBaseData[]> GetAllApps(CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<AppBaseData[]>("api/v1/apps", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<PointOfSaleAppData> GetPosApp(string appId, CancellationToken token = default)
|
||||
{
|
||||
if (appId == null) throw new ArgumentNullException(nameof(appId));
|
||||
return await SendHttpRequest<PointOfSaleAppData>($"api/v1/apps/pos/{appId}", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<CrowdfundAppData> GetCrowdfundApp(string appId, CancellationToken token = default)
|
||||
{
|
||||
if (appId == null) throw new ArgumentNullException(nameof(appId));
|
||||
return await SendHttpRequest<CrowdfundAppData>($"api/v1/apps/crowdfund/{appId}", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<AppSalesStats> GetAppSales(string appId, int numberOfDays = 7, CancellationToken token = default)
|
||||
{
|
||||
if (appId == null) throw new ArgumentNullException(nameof(appId));
|
||||
var queryPayload = new Dictionary<string, object> { { nameof(numberOfDays), numberOfDays } };
|
||||
return await SendHttpRequest<AppSalesStats>($"api/v1/apps/{appId}/sales", queryPayload, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<List<AppItemStats>> GetAppTopItems(string appId, int offset = 0, int count = 10, CancellationToken token = default)
|
||||
{
|
||||
if (appId == null) throw new ArgumentNullException(nameof(appId));
|
||||
var queryPayload = new Dictionary<string, object> { { nameof(offset), offset }, { nameof(count), count } };
|
||||
return await SendHttpRequest<List<AppItemStats>>($"api/v1/apps/{appId}/top-items", queryPayload, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task DeleteApp(string appId, CancellationToken token = default)
|
||||
{
|
||||
if (appId == null) throw new ArgumentNullException(nameof(appId));
|
||||
await SendHttpRequest($"api/v1/apps/{appId}", null, HttpMethod.Delete, token);
|
||||
}
|
||||
|
||||
public virtual async Task<FileData> UploadAppItemImage(string appId, string filePath, string mimeType, CancellationToken token = default)
|
||||
{
|
||||
return await UploadFileRequest<FileData>($"api/v1/apps/{appId}/image", filePath, mimeType, "file", HttpMethod.Post, token);
|
||||
}
|
||||
|
||||
public virtual async Task DeleteAppItemImage(string appId, string fileId, CancellationToken token = default)
|
||||
{
|
||||
await SendHttpRequest($"api/v1/apps/{appId}/image/{fileId}", null, HttpMethod.Delete, token);
|
||||
}
|
||||
}
|
@ -1,29 +1,33 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BTCPayServer.Client;
|
||||
|
||||
public partial class BTCPayServerClient
|
||||
namespace BTCPayServer.Client
|
||||
{
|
||||
public static Uri GenerateAuthorizeUri(Uri btcpayHost, string[] permissions, bool strict = true,
|
||||
bool selectiveStores = false, (string ApplicationIdentifier, Uri Redirect) applicationDetails = default)
|
||||
public partial class BTCPayServerClient
|
||||
{
|
||||
var result = new UriBuilder(btcpayHost) { Path = "api-keys/authorize" };
|
||||
AppendPayloadToQuery(result,
|
||||
new Dictionary<string, object>
|
||||
{
|
||||
{"strict", strict}, {"selectiveStores", selectiveStores}, {"permissions", permissions}
|
||||
});
|
||||
|
||||
if (applicationDetails.Redirect != null)
|
||||
public static Uri GenerateAuthorizeUri(Uri btcpayHost, string[] permissions, bool strict = true,
|
||||
bool selectiveStores = false, (string ApplicationIdentifier, Uri Redirect) applicationDetails = default)
|
||||
{
|
||||
AppendPayloadToQuery(result, new KeyValuePair<string, object>("redirect", applicationDetails.Redirect));
|
||||
if (!string.IsNullOrEmpty(applicationDetails.ApplicationIdentifier))
|
||||
{
|
||||
AppendPayloadToQuery(result, new KeyValuePair<string, object>("applicationIdentifier", applicationDetails.ApplicationIdentifier));
|
||||
}
|
||||
}
|
||||
var result = new UriBuilder(btcpayHost);
|
||||
result.Path = "api-keys/authorize";
|
||||
|
||||
return result.Uri;
|
||||
AppendPayloadToQuery(result,
|
||||
new Dictionary<string, object>()
|
||||
{
|
||||
{"strict", strict}, {"selectiveStores", selectiveStores}, {"permissions", permissions}
|
||||
});
|
||||
|
||||
if (applicationDetails.Redirect != null)
|
||||
{
|
||||
AppendPayloadToQuery(result, new KeyValuePair<string, object>("redirect", applicationDetails.Redirect));
|
||||
if (!string.IsNullOrEmpty(applicationDetails.ApplicationIdentifier))
|
||||
{
|
||||
AppendPayloadToQuery(result, new KeyValuePair<string, object>("applicationIdentifier", applicationDetails.ApplicationIdentifier));
|
||||
}
|
||||
}
|
||||
|
||||
return result.Uri;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,29 +0,0 @@
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
|
||||
namespace BTCPayServer.Client;
|
||||
|
||||
public partial class BTCPayServerClient
|
||||
{
|
||||
public virtual async Task<FileData[]> GetFiles(CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<FileData[]>("api/v1/files", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<FileData> GetFile(string fileId, CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<FileData>($"api/v1/files/{fileId}", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<FileData> UploadFile(string filePath, string mimeType, CancellationToken token = default)
|
||||
{
|
||||
return await UploadFileRequest<FileData>("api/v1/files", filePath, mimeType, "file", HttpMethod.Post, token);
|
||||
}
|
||||
|
||||
public virtual async Task DeleteFile(string fileId, CancellationToken token = default)
|
||||
{
|
||||
await SendHttpRequest($"api/v1/files/{fileId}", null, HttpMethod.Delete, token);
|
||||
}
|
||||
}
|
@ -1,14 +1,15 @@
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
|
||||
namespace BTCPayServer.Client;
|
||||
|
||||
public partial class BTCPayServerClient
|
||||
namespace BTCPayServer.Client
|
||||
{
|
||||
public virtual async Task<ApiHealthData> GetHealth(CancellationToken token = default)
|
||||
public partial class BTCPayServerClient
|
||||
{
|
||||
return await SendHttpRequest<ApiHealthData>("api/v1/health", null, HttpMethod.Get, token);
|
||||
public virtual async Task<ApiHealthData> GetHealth(CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest("api/v1/health"), token);
|
||||
return await HandleResponse<ApiHealthData>(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,107 +1,71 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
using NBitcoin;
|
||||
|
||||
namespace BTCPayServer.Client;
|
||||
|
||||
public partial class BTCPayServerClient
|
||||
namespace BTCPayServer.Client
|
||||
{
|
||||
public virtual async Task<IEnumerable<InvoiceData>> GetInvoices(string storeId, string[] orderId = null,
|
||||
InvoiceStatus[] status = null,
|
||||
DateTimeOffset? startDate = null,
|
||||
DateTimeOffset? endDate = null,
|
||||
string textSearch = null,
|
||||
bool includeArchived = false,
|
||||
int? skip = null,
|
||||
int? take = null,
|
||||
CancellationToken token = default)
|
||||
public partial class BTCPayServerClient
|
||||
{
|
||||
var queryPayload = new Dictionary<string, object> { { nameof(includeArchived), includeArchived } };
|
||||
if (startDate is { } s)
|
||||
queryPayload.Add(nameof(startDate), Utils.DateTimeToUnixTime(s));
|
||||
if (endDate is { } e)
|
||||
queryPayload.Add(nameof(endDate), Utils.DateTimeToUnixTime(e));
|
||||
if (orderId != null)
|
||||
queryPayload.Add(nameof(orderId), orderId);
|
||||
if (textSearch != null)
|
||||
queryPayload.Add(nameof(textSearch), textSearch);
|
||||
if (status != null)
|
||||
queryPayload.Add(nameof(status), status.Select(s => s.ToString().ToLower()).ToArray());
|
||||
if (skip != null)
|
||||
queryPayload.Add(nameof(skip), skip);
|
||||
if (take != null)
|
||||
queryPayload.Add(nameof(take), take);
|
||||
|
||||
return await SendHttpRequest<IEnumerable<InvoiceData>>($"api/v1/stores/{storeId}/invoices", queryPayload, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<InvoiceData> GetInvoice(string storeId, string invoiceId,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<InvoiceData>($"api/v1/stores/{storeId}/invoices/{invoiceId}", null, HttpMethod.Get, token);
|
||||
}
|
||||
public virtual async Task<InvoicePaymentMethodDataModel[]> GetInvoicePaymentMethods(string storeId, string invoiceId,
|
||||
bool onlyAccountedPayments = true, bool includeSensitive = false,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
var queryPayload = new Dictionary<string, object>
|
||||
public virtual async Task<IEnumerable<InvoiceData>> GetInvoices(string storeId, bool includeArchived = false,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
{ nameof(onlyAccountedPayments), onlyAccountedPayments },
|
||||
{ nameof(includeSensitive), includeSensitive }
|
||||
};
|
||||
return await SendHttpRequest<InvoicePaymentMethodDataModel[]>($"api/v1/stores/{storeId}/invoices/{invoiceId}/payment-methods", queryPayload, HttpMethod.Get, token);
|
||||
}
|
||||
var response =
|
||||
await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}/invoices",
|
||||
new Dictionary<string, object>() {{nameof(includeArchived), includeArchived}}), token);
|
||||
return await HandleResponse<IEnumerable<InvoiceData>>(response);
|
||||
}
|
||||
|
||||
public virtual async Task ArchiveInvoice(string storeId, string invoiceId,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
await SendHttpRequest($"api/v1/stores/{storeId}/invoices/{invoiceId}", null, HttpMethod.Delete, token);
|
||||
}
|
||||
public virtual async Task<InvoiceData> GetInvoice(string storeId, string invoiceId,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}/invoices/{invoiceId}"), token);
|
||||
return await HandleResponse<InvoiceData>(response);
|
||||
}
|
||||
|
||||
public virtual async Task<InvoiceData> CreateInvoice(string storeId,
|
||||
CreateInvoiceRequest request, CancellationToken token = default)
|
||||
{
|
||||
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||
return await SendHttpRequest<InvoiceData>($"api/v1/stores/{storeId}/invoices", request, HttpMethod.Post, token);
|
||||
}
|
||||
public virtual async Task ArchiveInvoice(string storeId, string invoiceId,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}/invoices/{invoiceId}",
|
||||
method: HttpMethod.Delete), token);
|
||||
await HandleResponse(response);
|
||||
}
|
||||
|
||||
public virtual async Task<InvoiceData> UpdateInvoice(string storeId, string invoiceId,
|
||||
UpdateInvoiceRequest request, CancellationToken token = default)
|
||||
{
|
||||
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||
return await SendHttpRequest<InvoiceData>($"api/v1/stores/{storeId}/invoices/{invoiceId}", request, HttpMethod.Put, token);
|
||||
}
|
||||
public virtual async Task<InvoiceData> CreateInvoice(string storeId,
|
||||
CreateInvoiceRequest request, CancellationToken token = default)
|
||||
{
|
||||
if (request == null)
|
||||
throw new ArgumentNullException(nameof(request));
|
||||
var response = await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}/invoices", bodyPayload: request,
|
||||
method: HttpMethod.Post), token);
|
||||
return await HandleResponse<InvoiceData>(response);
|
||||
}
|
||||
|
||||
public virtual async Task<InvoiceData> MarkInvoiceStatus(string storeId, string invoiceId,
|
||||
MarkInvoiceStatusRequest request, CancellationToken token = default)
|
||||
{
|
||||
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||
if (request.Status != InvoiceStatus.Settled && request.Status != InvoiceStatus.Invalid) throw new ArgumentOutOfRangeException(nameof(request.Status), "Status can only be Invalid or Complete");
|
||||
return await SendHttpRequest<InvoiceData>($"api/v1/stores/{storeId}/invoices/{invoiceId}/status", request, HttpMethod.Post, token);
|
||||
}
|
||||
public virtual async Task<InvoiceData> MarkInvoiceStatus(string storeId, string invoiceId,
|
||||
MarkInvoiceStatusRequest request, CancellationToken token = default)
|
||||
{
|
||||
if (request == null)
|
||||
throw new ArgumentNullException(nameof(request));
|
||||
if (request.Status!= InvoiceStatus.Complete && request.Status!= InvoiceStatus.Invalid)
|
||||
throw new ArgumentOutOfRangeException(nameof(request.Status), "Status can only be Invalid or Complete");
|
||||
var response = await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}/invoices/{invoiceId}/status", bodyPayload: request,
|
||||
method: HttpMethod.Post), token);
|
||||
return await HandleResponse<InvoiceData>(response);
|
||||
}
|
||||
|
||||
public virtual async Task<InvoiceData> UnarchiveInvoice(string storeId, string invoiceId, CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<InvoiceData>($"api/v1/stores/{storeId}/invoices/{invoiceId}/unarchive", null, HttpMethod.Post, token);
|
||||
}
|
||||
|
||||
public virtual async Task ActivateInvoicePaymentMethod(string storeId, string invoiceId, string paymentMethod, CancellationToken token = default)
|
||||
{
|
||||
await SendHttpRequest($"api/v1/stores/{storeId}/invoices/{invoiceId}/payment-methods/{paymentMethod}/activate", null, HttpMethod.Post, token);
|
||||
}
|
||||
|
||||
public virtual async Task<PullPaymentData> RefundInvoice(
|
||||
string storeId,
|
||||
string invoiceId,
|
||||
RefundInvoiceRequest request,
|
||||
CancellationToken token = default
|
||||
)
|
||||
{
|
||||
return await SendHttpRequest<PullPaymentData>($"api/v1/stores/{storeId}/invoices/{invoiceId}/refund", request, HttpMethod.Post, token);
|
||||
public virtual async Task<InvoiceData> UnarchiveInvoice(string storeId, string invoiceId, CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}/invoices/{invoiceId}/unarchive",
|
||||
method: HttpMethod.Post), token);
|
||||
return await HandleResponse<InvoiceData>(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,108 +5,87 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
|
||||
namespace BTCPayServer.Client;
|
||||
|
||||
public partial class BTCPayServerClient
|
||||
namespace BTCPayServer.Client
|
||||
{
|
||||
public virtual async Task<LightningNodeInformationData> GetLightningNodeInfo(string cryptoCode,
|
||||
CancellationToken token = default)
|
||||
public partial class BTCPayServerClient
|
||||
{
|
||||
return await SendHttpRequest<LightningNodeInformationData>($"api/v1/server/lightning/{cryptoCode}/info", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<LightningNodeBalanceData> GetLightningNodeBalance(string cryptoCode,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<LightningNodeBalanceData>($"api/v1/server/lightning/{cryptoCode}/balance", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<HistogramData> GetLightningNodeHistogram(string cryptoCode, HistogramType? type = null,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
var queryPayload = type == null ? null : new Dictionary<string, object> { { "type", type.ToString() } };
|
||||
return await SendHttpRequest<HistogramData>($"api/v1/server/lightning/{cryptoCode}/histogram", queryPayload, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task ConnectToLightningNode(string cryptoCode, ConnectToNodeRequest request,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||
await SendHttpRequest($"api/v1/server/lightning/{cryptoCode}/connect", request, HttpMethod.Post, token);
|
||||
}
|
||||
|
||||
public virtual async Task<IEnumerable<LightningChannelData>> GetLightningNodeChannels(string cryptoCode,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<IEnumerable<LightningChannelData>>($"api/v1/server/lightning/{cryptoCode}/channels", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task OpenLightningChannel(string cryptoCode, OpenLightningChannelRequest request,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
await SendHttpRequest($"api/v1/server/lightning/{cryptoCode}/channels", request, HttpMethod.Post, token);
|
||||
}
|
||||
|
||||
public virtual async Task<string> GetLightningDepositAddress(string cryptoCode, CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<string>($"api/v1/server/lightning/{cryptoCode}/address", null, HttpMethod.Post, token);
|
||||
}
|
||||
|
||||
public virtual async Task<LightningPaymentData> PayLightningInvoice(string cryptoCode, PayLightningInvoiceRequest request,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||
return await SendHttpRequest<LightningPaymentData>($"api/v1/server/lightning/{cryptoCode}/invoices/pay", request, HttpMethod.Post, token);
|
||||
}
|
||||
|
||||
public virtual async Task<LightningPaymentData> GetLightningPayment(string cryptoCode,
|
||||
string paymentHash, CancellationToken token = default)
|
||||
{
|
||||
if (paymentHash == null) throw new ArgumentNullException(nameof(paymentHash));
|
||||
return await SendHttpRequest<LightningPaymentData>($"api/v1/server/lightning/{cryptoCode}/payments/{paymentHash}", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<LightningInvoiceData> GetLightningInvoice(string cryptoCode,
|
||||
string invoiceId, CancellationToken token = default)
|
||||
{
|
||||
if (invoiceId == null) throw new ArgumentNullException(nameof(invoiceId));
|
||||
return await SendHttpRequest<LightningInvoiceData>($"api/v1/server/lightning/{cryptoCode}/invoices/{invoiceId}", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<LightningInvoiceData[]> GetLightningInvoices(string cryptoCode,
|
||||
bool? pendingOnly = null, long? offsetIndex = null, CancellationToken token = default)
|
||||
{
|
||||
var queryPayload = new Dictionary<string, object>();
|
||||
if (pendingOnly is bool v)
|
||||
public async Task<LightningNodeInformationData> GetLightningNodeInfo(string cryptoCode,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
queryPayload.Add("pendingOnly", v.ToString());
|
||||
var response = await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/server/lightning/{cryptoCode}/info",
|
||||
method: HttpMethod.Get), token);
|
||||
return await HandleResponse<LightningNodeInformationData>(response);
|
||||
}
|
||||
if (offsetIndex is > 0)
|
||||
{
|
||||
queryPayload.Add("offsetIndex", offsetIndex);
|
||||
}
|
||||
return await SendHttpRequest<LightningInvoiceData[]>($"api/v1/server/lightning/{cryptoCode}/invoices", queryPayload, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<LightningPaymentData[]> GetLightningPayments(string cryptoCode,
|
||||
bool? includePending = null, long? offsetIndex = null, CancellationToken token = default)
|
||||
{
|
||||
var queryPayload = new Dictionary<string, object>();
|
||||
if (includePending is bool v)
|
||||
public async Task ConnectToLightningNode(string cryptoCode, ConnectToNodeRequest request,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
queryPayload.Add("includePending", v.ToString());
|
||||
if (request == null)
|
||||
throw new ArgumentNullException(nameof(request));
|
||||
var response = await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/server/lightning/{cryptoCode}/connect", bodyPayload: request,
|
||||
method: HttpMethod.Post), token);
|
||||
await HandleResponse(response);
|
||||
}
|
||||
if (offsetIndex is > 0)
|
||||
{
|
||||
queryPayload.Add("offsetIndex", offsetIndex);
|
||||
}
|
||||
return await SendHttpRequest<LightningPaymentData[]>($"api/v1/server/lightning/{cryptoCode}/payments", queryPayload, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<LightningInvoiceData> CreateLightningInvoice(string cryptoCode, CreateLightningInvoiceRequest request,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||
return await SendHttpRequest<LightningInvoiceData>($"api/v1/server/lightning/{cryptoCode}/invoices", request, HttpMethod.Post, token);
|
||||
public async Task<IEnumerable<LightningChannelData>> GetLightningNodeChannels(string cryptoCode,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/server/lightning/{cryptoCode}/channels",
|
||||
method: HttpMethod.Get), token);
|
||||
return await HandleResponse<IEnumerable<LightningChannelData>>(response);
|
||||
}
|
||||
|
||||
public async Task<string> OpenLightningChannel(string cryptoCode, OpenLightningChannelRequest request,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/server/lightning/{cryptoCode}/channels", bodyPayload: request,
|
||||
method: HttpMethod.Post), token);
|
||||
return await HandleResponse<string>(response);
|
||||
}
|
||||
|
||||
public async Task<string> GetLightningDepositAddress(string cryptoCode, CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/server/lightning/{cryptoCode}/address", method: HttpMethod.Post), token);
|
||||
return await HandleResponse<string>(response);
|
||||
}
|
||||
|
||||
|
||||
public async Task PayLightningInvoice(string cryptoCode, PayLightningInvoiceRequest request,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
if (request == null)
|
||||
throw new ArgumentNullException(nameof(request));
|
||||
var response = await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/server/lightning/{cryptoCode}/invoices/pay", bodyPayload: request,
|
||||
method: HttpMethod.Post), token);
|
||||
await HandleResponse(response);
|
||||
}
|
||||
|
||||
public async Task<LightningInvoiceData> GetLightningInvoice(string cryptoCode,
|
||||
string invoiceId, CancellationToken token = default)
|
||||
{
|
||||
if (invoiceId == null)
|
||||
throw new ArgumentNullException(nameof(invoiceId));
|
||||
var response = await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/server/lightning/{cryptoCode}/invoices/{invoiceId}",
|
||||
method: HttpMethod.Get), token);
|
||||
return await HandleResponse<LightningInvoiceData>(response);
|
||||
}
|
||||
|
||||
public async Task<LightningInvoiceData> CreateLightningInvoice(string cryptoCode, CreateLightningInvoiceRequest request,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
if (request == null)
|
||||
throw new ArgumentNullException(nameof(request));
|
||||
var response = await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/server/lightning/{cryptoCode}/invoices", bodyPayload: request,
|
||||
method: HttpMethod.Post), token);
|
||||
return await HandleResponse<LightningInvoiceData>(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,109 +5,88 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
|
||||
namespace BTCPayServer.Client;
|
||||
|
||||
public partial class BTCPayServerClient
|
||||
namespace BTCPayServer.Client
|
||||
{
|
||||
public virtual async Task<LightningNodeInformationData> GetLightningNodeInfo(string storeId, string cryptoCode,
|
||||
CancellationToken token = default)
|
||||
public partial class BTCPayServerClient
|
||||
{
|
||||
return await SendHttpRequest<LightningNodeInformationData>($"api/v1/stores/{storeId}/lightning/{cryptoCode}/info", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<LightningNodeBalanceData> GetLightningNodeBalance(string storeId, string cryptoCode,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<LightningNodeBalanceData>($"api/v1/stores/{storeId}/lightning/{cryptoCode}/balance", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<HistogramData> GetLightningNodeHistogram(string storeId, string cryptoCode, HistogramType? type = null,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
var queryPayload = type == null ? null : new Dictionary<string, object> { { "type", type.ToString() } };
|
||||
return await SendHttpRequest<HistogramData>($"api/v1/stores/{storeId}/lightning/{cryptoCode}/histogram", queryPayload, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task ConnectToLightningNode(string storeId, string cryptoCode, ConnectToNodeRequest request,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||
await SendHttpRequest($"api/v1/stores/{storeId}/lightning/{cryptoCode}/connect", request, HttpMethod.Post, token);
|
||||
}
|
||||
|
||||
public virtual async Task<IEnumerable<LightningChannelData>> GetLightningNodeChannels(string storeId, string cryptoCode,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<IEnumerable<LightningChannelData>>($"api/v1/stores/{storeId}/lightning/{cryptoCode}/channels", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task OpenLightningChannel(string storeId, string cryptoCode, OpenLightningChannelRequest request,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
await SendHttpRequest($"api/v1/stores/{storeId}/lightning/{cryptoCode}/channels", request, HttpMethod.Post, token);
|
||||
}
|
||||
|
||||
public virtual async Task<string> GetLightningDepositAddress(string storeId, string cryptoCode,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<string>($"api/v1/stores/{storeId}/lightning/{cryptoCode}/address", null, HttpMethod.Post, token);
|
||||
}
|
||||
|
||||
public virtual async Task<LightningPaymentData> PayLightningInvoice(string storeId, string cryptoCode, PayLightningInvoiceRequest request,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||
return await SendHttpRequest<LightningPaymentData>($"api/v1/stores/{storeId}/lightning/{cryptoCode}/invoices/pay", request, HttpMethod.Post, token);
|
||||
}
|
||||
|
||||
public virtual async Task<LightningPaymentData> GetLightningPayment(string storeId, string cryptoCode,
|
||||
string paymentHash, CancellationToken token = default)
|
||||
{
|
||||
if (paymentHash == null) throw new ArgumentNullException(nameof(paymentHash));
|
||||
return await SendHttpRequest<LightningPaymentData>($"api/v1/stores/{storeId}/lightning/{cryptoCode}/payments/{paymentHash}", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<LightningInvoiceData> GetLightningInvoice(string storeId, string cryptoCode,
|
||||
string invoiceId, CancellationToken token = default)
|
||||
{
|
||||
if (invoiceId == null) throw new ArgumentNullException(nameof(invoiceId));
|
||||
return await SendHttpRequest<LightningInvoiceData>($"api/v1/stores/{storeId}/lightning/{cryptoCode}/invoices/{invoiceId}", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<LightningInvoiceData[]> GetLightningInvoices(string storeId, string cryptoCode,
|
||||
bool? pendingOnly = null, long? offsetIndex = null, CancellationToken token = default)
|
||||
{
|
||||
var queryPayload = new Dictionary<string, object>();
|
||||
if (pendingOnly is bool v)
|
||||
public async Task<LightningNodeInformationData> GetLightningNodeInfo(string storeId, string cryptoCode,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
queryPayload.Add("pendingOnly", v.ToString());
|
||||
var response = await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}/lightning/{cryptoCode}/info",
|
||||
method: HttpMethod.Get), token);
|
||||
return await HandleResponse<LightningNodeInformationData>(response);
|
||||
}
|
||||
if (offsetIndex is > 0)
|
||||
{
|
||||
queryPayload.Add("offsetIndex", offsetIndex);
|
||||
}
|
||||
return await SendHttpRequest<LightningInvoiceData[]>($"api/v1/stores/{storeId}/lightning/{cryptoCode}/invoices", queryPayload, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<LightningPaymentData[]> GetLightningPayments(string storeId, string cryptoCode,
|
||||
bool? includePending = null, long? offsetIndex = null, CancellationToken token = default)
|
||||
{
|
||||
var queryPayload = new Dictionary<string, object>();
|
||||
if (includePending is bool v)
|
||||
public async Task ConnectToLightningNode(string storeId, string cryptoCode, ConnectToNodeRequest request,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
queryPayload.Add("includePending", v.ToString());
|
||||
if (request == null)
|
||||
throw new ArgumentNullException(nameof(request));
|
||||
var response = await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}/lightning/{cryptoCode}/connect", bodyPayload: request,
|
||||
method: HttpMethod.Post), token);
|
||||
await HandleResponse(response);
|
||||
}
|
||||
if (offsetIndex is > 0)
|
||||
{
|
||||
queryPayload.Add("offsetIndex", offsetIndex);
|
||||
}
|
||||
return await SendHttpRequest<LightningPaymentData[]>($"api/v1/stores/{storeId}/lightning/{cryptoCode}/payments", queryPayload, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<LightningInvoiceData> CreateLightningInvoice(string storeId, string cryptoCode,
|
||||
CreateLightningInvoiceRequest request, CancellationToken token = default)
|
||||
{
|
||||
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||
return await SendHttpRequest<LightningInvoiceData>($"api/v1/stores/{storeId}/lightning/{cryptoCode}/invoices", request, HttpMethod.Post, token);
|
||||
public async Task<IEnumerable<LightningChannelData>> GetLightningNodeChannels(string storeId, string cryptoCode,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}/lightning/{cryptoCode}/channels",
|
||||
method: HttpMethod.Get), token);
|
||||
return await HandleResponse<IEnumerable<LightningChannelData>>(response);
|
||||
}
|
||||
|
||||
public async Task<string> OpenLightningChannel(string storeId, string cryptoCode, OpenLightningChannelRequest request,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}/lightning/{cryptoCode}/channels", bodyPayload: request,
|
||||
method: HttpMethod.Post), token);
|
||||
return await HandleResponse<string>(response);
|
||||
}
|
||||
|
||||
public async Task<string> GetLightningDepositAddress(string storeId, string cryptoCode,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}/lightning/{cryptoCode}/address", method: HttpMethod.Post),
|
||||
token);
|
||||
return await HandleResponse<string>(response);
|
||||
}
|
||||
|
||||
public async Task PayLightningInvoice(string storeId, string cryptoCode, PayLightningInvoiceRequest request,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
if (request == null)
|
||||
throw new ArgumentNullException(nameof(request));
|
||||
var response = await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}/lightning/{cryptoCode}/invoices/pay", bodyPayload: request,
|
||||
method: HttpMethod.Post), token);
|
||||
await HandleResponse(response);
|
||||
}
|
||||
|
||||
public async Task<LightningInvoiceData> GetLightningInvoice(string storeId, string cryptoCode,
|
||||
string invoiceId, CancellationToken token = default)
|
||||
{
|
||||
if (invoiceId == null)
|
||||
throw new ArgumentNullException(nameof(invoiceId));
|
||||
var response = await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}/lightning/{cryptoCode}/invoices/{invoiceId}",
|
||||
method: HttpMethod.Get), token);
|
||||
return await HandleResponse<LightningInvoiceData>(response);
|
||||
}
|
||||
|
||||
public async Task<LightningInvoiceData> CreateLightningInvoice(string storeId, string cryptoCode,
|
||||
CreateLightningInvoiceRequest request, CancellationToken token = default)
|
||||
{
|
||||
if (request == null)
|
||||
throw new ArgumentNullException(nameof(request));
|
||||
var response = await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}/lightning/{cryptoCode}/invoices", bodyPayload: request,
|
||||
method: HttpMethod.Post), token);
|
||||
return await HandleResponse<LightningInvoiceData>(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,34 +0,0 @@
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
|
||||
namespace BTCPayServer.Client;
|
||||
|
||||
public partial class BTCPayServerClient
|
||||
{
|
||||
public virtual async Task<LightningAddressData[]> GetStoreLightningAddresses(string storeId,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<LightningAddressData[]>($"api/v1/stores/{storeId}/lightning-addresses", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<LightningAddressData> GetStoreLightningAddress(string storeId, string username,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<LightningAddressData>($"api/v1/stores/{storeId}/lightning-addresses/{username}", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task RemoveStoreLightningAddress(string storeId, string username,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
await SendHttpRequest($"api/v1/stores/{storeId}/lightning-addresses/{username}", null, HttpMethod.Delete, token);
|
||||
}
|
||||
|
||||
public virtual async Task<LightningAddressData> AddOrUpdateStoreLightningAddress(string storeId,
|
||||
string username, LightningAddressData data,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<LightningAddressData>($"api/v1/stores/{storeId}/lightning-addresses/{username}", data, HttpMethod.Post, token);
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
|
||||
namespace BTCPayServer.Client;
|
||||
|
||||
public partial class BTCPayServerClient
|
||||
{
|
||||
public virtual async Task<PermissionMetadata[]> GetPermissionMetadata(CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<PermissionMetadata[]>("misc/permissions", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<Language[]> GetAvailableLanguages(CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<Language[]>("misc/lang", null, HttpMethod.Get, token);
|
||||
}
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
|
||||
namespace BTCPayServer.Client;
|
||||
|
||||
public partial class BTCPayServerClient
|
||||
{
|
||||
public virtual async Task<IEnumerable<NotificationData>> GetNotifications(bool? seen = null, int? skip = null,
|
||||
int? take = null, string[] storeId = null, CancellationToken token = default)
|
||||
{
|
||||
var queryPayload = new Dictionary<string, object>();
|
||||
if (seen != null)
|
||||
queryPayload.Add(nameof(seen), seen);
|
||||
if (skip != null)
|
||||
queryPayload.Add(nameof(skip), skip);
|
||||
if (take != null)
|
||||
queryPayload.Add(nameof(take), take);
|
||||
if (storeId != null)
|
||||
queryPayload.Add(nameof(storeId), storeId);
|
||||
return await SendHttpRequest<IEnumerable<NotificationData>>("api/v1/users/me/notifications", queryPayload, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<NotificationData> GetNotification(string notificationId,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<NotificationData>($"api/v1/users/me/notifications/{notificationId}", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<NotificationData> UpdateNotification(string notificationId, bool? seen,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<NotificationData>($"api/v1/users/me/notifications/{notificationId}", new UpdateNotification { Seen = seen }, HttpMethod.Put, token);
|
||||
}
|
||||
|
||||
public virtual async Task<NotificationSettingsData> GetNotificationSettings(CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<NotificationSettingsData>("api/v1/users/me/notification-settings", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<NotificationSettingsData> UpdateNotificationSettings(UpdateNotificationSettingsRequest request, CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<NotificationSettingsData>("api/v1/users/me/notification-settings", request, HttpMethod.Put, token);
|
||||
}
|
||||
|
||||
public virtual async Task RemoveNotification(string notificationId, CancellationToken token = default)
|
||||
{
|
||||
await SendHttpRequest($"api/v1/users/me/notifications/{notificationId}", null, HttpMethod.Delete, token);
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BTCPayServer.Client;
|
||||
|
||||
public partial class BTCPayServerClient
|
||||
{
|
||||
public virtual async Task<OnChainPaymentMethodPreviewResultData>
|
||||
PreviewProposedStoreOnChainPaymentMethodAddresses(
|
||||
string storeId, string paymentMethodId, string derivationScheme, int offset = 0,
|
||||
int amount = 10,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<UpdatePaymentMethodRequest, OnChainPaymentMethodPreviewResultData>($"api/v1/stores/{storeId}/payment-methods/{paymentMethodId}/wallet/preview",
|
||||
new Dictionary<string, object> { { "offset", offset }, { "amount", amount } },
|
||||
new UpdatePaymentMethodRequest { Config = JValue.CreateString(derivationScheme) },
|
||||
HttpMethod.Post, token);
|
||||
}
|
||||
|
||||
public virtual async Task<OnChainPaymentMethodPreviewResultData> PreviewStoreOnChainPaymentMethodAddresses(
|
||||
string storeId, string paymentMethodId, int offset = 0, int amount = 10,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<OnChainPaymentMethodPreviewResultData>($"api/v1/stores/{storeId}/payment-methods/{paymentMethodId}/wallet/preview",
|
||||
new Dictionary<string, object> { { "offset", offset }, { "amount", amount } }, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<GenerateOnChainWalletResponse> GenerateOnChainWallet(string storeId,
|
||||
string paymentMethodId, GenerateOnChainWalletRequest request,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<GenerateOnChainWalletResponse>($"api/v1/stores/{storeId}/payment-methods/{paymentMethodId}/wallet/generate", request, HttpMethod.Post, token);
|
||||
}
|
||||
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
|
||||
namespace BTCPayServer.Client;
|
||||
|
||||
public partial class BTCPayServerClient
|
||||
{
|
||||
public virtual async Task<OnChainWalletObjectData> GetOnChainWalletObject(string storeId, string cryptoCode, OnChainWalletObjectId objectId, bool? includeNeighbourData = null, CancellationToken token = default)
|
||||
{
|
||||
var parameters = new Dictionary<string, object>();
|
||||
if (includeNeighbourData is bool v)
|
||||
parameters.Add("includeNeighbourData", v);
|
||||
try
|
||||
{
|
||||
return await SendHttpRequest<OnChainWalletObjectData>($"api/v1/stores/{storeId}/payment-methods/{cryptoCode}-CHAIN/wallet/objects/{objectId.Type}/{objectId.Id}", parameters, HttpMethod.Get, token);
|
||||
}
|
||||
catch (GreenfieldAPIException err) when (err.APIError.Code == "wallet-object-not-found")
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public virtual async Task<OnChainWalletObjectData[]> GetOnChainWalletObjects(string storeId, string cryptoCode, GetWalletObjectsRequest query = null, CancellationToken token = default)
|
||||
{
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||
if (query?.Type is string s)
|
||||
parameters.Add("type", s);
|
||||
if (query?.Ids is string[] ids)
|
||||
parameters.Add("ids", ids);
|
||||
if (query?.IncludeNeighbourData is bool v)
|
||||
parameters.Add("includeNeighbourData", v);
|
||||
return await SendHttpRequest<OnChainWalletObjectData[]>($"api/v1/stores/{storeId}/payment-methods/{cryptoCode}-CHAIN/wallet/objects", parameters, HttpMethod.Get, token);
|
||||
}
|
||||
public virtual async Task RemoveOnChainWalletObject(string storeId, string cryptoCode, OnChainWalletObjectId objectId,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
await SendHttpRequest($"api/v1/stores/{storeId}/payment-methods/{cryptoCode}-CHAIN/wallet/objects/{objectId.Type}/{objectId.Id}", null, HttpMethod.Delete, token);
|
||||
}
|
||||
public virtual async Task<OnChainWalletObjectData> AddOrUpdateOnChainWalletObject(string storeId, string cryptoCode, AddOnChainWalletObjectRequest request,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<OnChainWalletObjectData>($"api/v1/stores/{storeId}/payment-methods/{cryptoCode}-CHAIN/wallet/objects", request, HttpMethod.Post, token);
|
||||
}
|
||||
|
||||
public virtual async Task AddOrUpdateOnChainWalletLink(string storeId, string cryptoCode,
|
||||
OnChainWalletObjectId objectId,
|
||||
AddOnChainWalletObjectLinkRequest request = null,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
await SendHttpRequest($"api/v1/stores/{storeId}/payment-methods/{cryptoCode}-CHAIN/wallet/objects/{objectId.Type}/{objectId.Id}/links", request, HttpMethod.Post, token);
|
||||
}
|
||||
|
||||
public virtual async Task RemoveOnChainWalletLinks(string storeId, string cryptoCode,
|
||||
OnChainWalletObjectId objectId,
|
||||
OnChainWalletObjectId link,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
await SendHttpRequest($"api/v1/stores/{storeId}/payment-methods/{cryptoCode}-CHAIN/wallet/objects/{objectId.Type}/{objectId.Id}/links/{link.Type}/{link.Id}", null, HttpMethod.Delete, token);
|
||||
}
|
||||
}
|
@ -1,119 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
using NBitcoin;
|
||||
|
||||
namespace BTCPayServer.Client;
|
||||
|
||||
public partial class BTCPayServerClient
|
||||
{
|
||||
public virtual async Task<OnChainWalletOverviewData> ShowOnChainWalletOverview(string storeId, string cryptoCode,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<OnChainWalletOverviewData>($"api/v1/stores/{storeId}/payment-methods/{cryptoCode}-CHAIN/wallet", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<HistogramData> GetOnChainWalletHistogram(string storeId, string cryptoCode, HistogramType? type = null,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
var queryPayload = type == null ? null : new Dictionary<string, object> { { "type", type.ToString() } };
|
||||
return await SendHttpRequest<HistogramData>($"api/v1/stores/{storeId}/payment-methods/{cryptoCode}-CHAIN/wallet/histogram", queryPayload, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<OnChainWalletFeeRateData> GetOnChainFeeRate(string storeId, string cryptoCode, int? blockTarget = null,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
var queryParams = new Dictionary<string, object>();
|
||||
if (blockTarget != null)
|
||||
{
|
||||
queryParams.Add("blockTarget", blockTarget);
|
||||
}
|
||||
return await SendHttpRequest<OnChainWalletFeeRateData>($"api/v1/stores/{storeId}/payment-methods/{cryptoCode}-CHAIN/wallet/feerate", queryParams, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<OnChainWalletAddressData> GetOnChainWalletReceiveAddress(string storeId, string cryptoCode, bool forceGenerate = false,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<OnChainWalletAddressData>($"api/v1/stores/{storeId}/payment-methods/{cryptoCode}-CHAIN/wallet/address", new Dictionary<string, object>
|
||||
{
|
||||
{"forceGenerate", forceGenerate}
|
||||
}, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task UnReserveOnChainWalletReceiveAddress(string storeId, string cryptoCode,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
await SendHttpRequest($"api/v1/stores/{storeId}/payment-methods/{cryptoCode}-CHAIN/wallet/address", null, HttpMethod.Delete, token);
|
||||
}
|
||||
|
||||
public virtual async Task<IEnumerable<OnChainWalletTransactionData>> ShowOnChainWalletTransactions(
|
||||
string storeId, string cryptoCode, TransactionStatus[] statusFilter = null, string labelFilter = null, int skip = 0,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
var query = new Dictionary<string, object>();
|
||||
if (statusFilter?.Any() is true)
|
||||
{
|
||||
query.Add(nameof(statusFilter), statusFilter);
|
||||
}
|
||||
if (labelFilter != null)
|
||||
{
|
||||
query.Add(nameof(labelFilter), labelFilter);
|
||||
}
|
||||
if (skip != 0)
|
||||
{
|
||||
query.Add(nameof(skip), skip);
|
||||
}
|
||||
return await SendHttpRequest<IEnumerable<OnChainWalletTransactionData>>($"api/v1/stores/{storeId}/payment-methods/{cryptoCode}-CHAIN/wallet/transactions", query, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<OnChainWalletTransactionData> GetOnChainWalletTransaction(
|
||||
string storeId, string cryptoCode, string transactionId,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<OnChainWalletTransactionData>($"api/v1/stores/{storeId}/payment-methods/{cryptoCode}-CHAIN/wallet/transactions/{transactionId}", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<OnChainWalletTransactionData> PatchOnChainWalletTransaction(
|
||||
string storeId, string cryptoCode, string transactionId,
|
||||
PatchOnChainTransactionRequest request,
|
||||
bool force = false, CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<PatchOnChainTransactionRequest, OnChainWalletTransactionData>($"api/v1/stores/{storeId}/payment-methods/{cryptoCode}-CHAIN/wallet/transactions/{transactionId}",
|
||||
new Dictionary<string, object> { {"force", force} }, request, HttpMethod.Patch, token);
|
||||
}
|
||||
|
||||
public virtual async Task<IEnumerable<OnChainWalletUTXOData>> GetOnChainWalletUTXOs(string storeId,
|
||||
string cryptoCode,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<IEnumerable<OnChainWalletUTXOData>>($"api/v1/stores/{storeId}/payment-methods/{cryptoCode}-CHAIN/wallet/utxos", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<OnChainWalletTransactionData> CreateOnChainTransaction(string storeId,
|
||||
string cryptoCode, CreateOnChainTransactionRequest request,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
if (!request.ProceedWithBroadcast)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(request.ProceedWithBroadcast),
|
||||
"Please use CreateOnChainTransactionButDoNotBroadcast when wanting to only create the transaction");
|
||||
}
|
||||
return await SendHttpRequest<OnChainWalletTransactionData>($"api/v1/stores/{storeId}/payment-methods/{cryptoCode}-CHAIN/wallet/transactions", request, HttpMethod.Post, token);
|
||||
}
|
||||
|
||||
public virtual async Task<Transaction> CreateOnChainTransactionButDoNotBroadcast(string storeId,
|
||||
string cryptoCode, CreateOnChainTransactionRequest request, Network network,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
if (request.ProceedWithBroadcast)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(request.ProceedWithBroadcast),
|
||||
"Please use CreateOnChainTransaction when wanting to also broadcast the transaction");
|
||||
}
|
||||
return Transaction.Parse(await SendHttpRequest<string>($"api/v1/stores/{storeId}/payment-methods/{cryptoCode}-CHAIN/wallet/transactions", request, HttpMethod.Post, token), network);
|
||||
}
|
||||
}
|
@ -5,49 +5,58 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
|
||||
namespace BTCPayServer.Client;
|
||||
|
||||
public partial class BTCPayServerClient
|
||||
namespace BTCPayServer.Client
|
||||
{
|
||||
public virtual async Task<IEnumerable<PaymentRequestData>> GetPaymentRequests(string storeId,
|
||||
bool includeArchived = false,
|
||||
CancellationToken token = default)
|
||||
public partial class BTCPayServerClient
|
||||
{
|
||||
return await SendHttpRequest<IEnumerable<PaymentRequestData>>($"api/v1/stores/{storeId}/payment-requests",
|
||||
new Dictionary<string, object> { { nameof(includeArchived), includeArchived } }, HttpMethod.Get, token);
|
||||
}
|
||||
public virtual async Task<IEnumerable<PaymentRequestData>> GetPaymentRequests(string storeId,
|
||||
bool includeArchived = false,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
var response =
|
||||
await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}/payment-requests",
|
||||
new Dictionary<string, object>() {{nameof(includeArchived), includeArchived}}), token);
|
||||
return await HandleResponse<IEnumerable<PaymentRequestData>>(response);
|
||||
}
|
||||
|
||||
public virtual async Task<PaymentRequestData> GetPaymentRequest(string storeId, string paymentRequestId,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<PaymentRequestData>($"api/v1/stores/{storeId}/payment-requests/{paymentRequestId}", null, HttpMethod.Get, token);
|
||||
}
|
||||
public virtual async Task<PaymentRequestData> GetPaymentRequest(string storeId, string paymentRequestId,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}/payment-requests/{paymentRequestId}"), token);
|
||||
return await HandleResponse<PaymentRequestData>(response);
|
||||
}
|
||||
|
||||
public virtual async Task ArchivePaymentRequest(string storeId, string paymentRequestId,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
await SendHttpRequest($"api/v1/stores/{storeId}/payment-requests/{paymentRequestId}", null, HttpMethod.Delete, token);
|
||||
}
|
||||
public virtual async Task ArchivePaymentRequest(string storeId, string paymentRequestId,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}/payment-requests/{paymentRequestId}",
|
||||
method: HttpMethod.Delete), token);
|
||||
await HandleResponse(response);
|
||||
}
|
||||
|
||||
public virtual async Task<Client.Models.InvoiceData> PayPaymentRequest(string storeId, string paymentRequestId, PayPaymentRequestRequest request, CancellationToken token = default)
|
||||
{
|
||||
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||
if (storeId is null) throw new ArgumentNullException(nameof(storeId));
|
||||
if (paymentRequestId is null) throw new ArgumentNullException(nameof(paymentRequestId));
|
||||
return await SendHttpRequest<InvoiceData>($"api/v1/stores/{storeId}/payment-requests/{paymentRequestId}/pay", request, HttpMethod.Post, token);
|
||||
}
|
||||
public virtual async Task<PaymentRequestData> CreatePaymentRequest(string storeId,
|
||||
CreatePaymentRequestRequest request, CancellationToken token = default)
|
||||
{
|
||||
if (request == null)
|
||||
throw new ArgumentNullException(nameof(request));
|
||||
var response = await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}/payment-requests", bodyPayload: request,
|
||||
method: HttpMethod.Post), token);
|
||||
return await HandleResponse<PaymentRequestData>(response);
|
||||
}
|
||||
|
||||
public virtual async Task<PaymentRequestData> CreatePaymentRequest(string storeId,
|
||||
CreatePaymentRequestRequest request, CancellationToken token = default)
|
||||
{
|
||||
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||
return await SendHttpRequest<PaymentRequestData>($"api/v1/stores/{storeId}/payment-requests", request, HttpMethod.Post, token);
|
||||
}
|
||||
|
||||
public virtual async Task<PaymentRequestData> UpdatePaymentRequest(string storeId, string paymentRequestId,
|
||||
UpdatePaymentRequestRequest request, CancellationToken token = default)
|
||||
{
|
||||
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||
return await SendHttpRequest<PaymentRequestData>($"api/v1/stores/{storeId}/payment-requests/{paymentRequestId}", request, HttpMethod.Put, token);
|
||||
public virtual async Task<PaymentRequestData> UpdatePaymentRequest(string storeId, string paymentRequestId,
|
||||
UpdatePaymentRequestRequest request, CancellationToken token = default)
|
||||
{
|
||||
if (request == null)
|
||||
throw new ArgumentNullException(nameof(request));
|
||||
var response = await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}/payment-requests/{paymentRequestId}", bodyPayload: request,
|
||||
method: HttpMethod.Put), token);
|
||||
return await HandleResponse<PaymentRequestData>(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +0,0 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
|
||||
namespace BTCPayServer.Client;
|
||||
|
||||
public partial class BTCPayServerClient
|
||||
{
|
||||
public virtual async Task<IEnumerable<PayoutProcessorData>> GetPayoutProcessors(CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<IEnumerable<PayoutProcessorData>>("api/v1/payout-processors", null, HttpMethod.Get, token);
|
||||
}
|
||||
}
|
@ -5,90 +5,57 @@ using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using BTCPayServer.Client.Models;
|
||||
|
||||
namespace BTCPayServer.Client;
|
||||
|
||||
public partial class BTCPayServerClient
|
||||
namespace BTCPayServer.Client
|
||||
{
|
||||
public virtual async Task<PullPaymentData> CreatePullPayment(string storeId, CreatePullPaymentRequest request, CancellationToken cancellationToken = default)
|
||||
public partial class BTCPayServerClient
|
||||
{
|
||||
return await SendHttpRequest<PullPaymentData>($"api/v1/stores/{HttpUtility.UrlEncode(storeId)}/pull-payments", request, HttpMethod.Post, cancellationToken);
|
||||
}
|
||||
public async Task<PullPaymentData> CreatePullPayment(string storeId, CreatePullPaymentRequest request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{HttpUtility.UrlEncode(storeId)}/pull-payments", bodyPayload: request, method: HttpMethod.Post), cancellationToken);
|
||||
return await HandleResponse<PullPaymentData>(response);
|
||||
}
|
||||
public async Task<PullPaymentData> GetPullPayment(string pullPaymentId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/pull-payments/{HttpUtility.UrlEncode(pullPaymentId)}", method: HttpMethod.Get), cancellationToken);
|
||||
return await HandleResponse<PullPaymentData>(response);
|
||||
}
|
||||
|
||||
public virtual async Task<PullPaymentData> GetPullPayment(string pullPaymentId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await SendHttpRequest<PullPaymentData>($"api/v1/pull-payments/{HttpUtility.UrlEncode(pullPaymentId)}", null, HttpMethod.Get, cancellationToken);
|
||||
}
|
||||
public async Task<PullPaymentData[]> GetPullPayments(string storeId, bool includeArchived = false, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Dictionary<string, object> query = new Dictionary<string, object>();
|
||||
query.Add("includeArchived", includeArchived);
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{HttpUtility.UrlEncode(storeId)}/pull-payments", queryPayload: query, method: HttpMethod.Get), cancellationToken);
|
||||
return await HandleResponse<PullPaymentData[]>(response);
|
||||
}
|
||||
|
||||
public virtual async Task<RegisterBoltcardResponse> RegisterBoltcard(string pullPaymentId, RegisterBoltcardRequest request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await SendHttpRequest<RegisterBoltcardResponse>($"api/v1/pull-payments/{HttpUtility.UrlEncode(pullPaymentId)}/boltcards", request, HttpMethod.Post, cancellationToken);
|
||||
}
|
||||
public async Task ArchivePullPayment(string storeId, string pullPaymentId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{HttpUtility.UrlEncode(storeId)}/pull-payments/{HttpUtility.UrlEncode(pullPaymentId)}", method: HttpMethod.Delete), cancellationToken);
|
||||
await HandleResponse(response);
|
||||
}
|
||||
|
||||
public virtual async Task<PullPaymentData[]> GetPullPayments(string storeId, bool includeArchived = false, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var query = new Dictionary<string, object> { { "includeArchived", includeArchived } };
|
||||
return await SendHttpRequest<PullPaymentData[]>($"api/v1/stores/{HttpUtility.UrlEncode(storeId)}/pull-payments", query, HttpMethod.Get, cancellationToken);
|
||||
}
|
||||
public async Task<PayoutData[]> GetPayouts(string pullPaymentId, bool includeCancelled = false, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Dictionary<string, object> query = new Dictionary<string, object>();
|
||||
query.Add("includeCancelled", includeCancelled);
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/pull-payments/{HttpUtility.UrlEncode(pullPaymentId)}/payouts", queryPayload: query, method: HttpMethod.Get), cancellationToken);
|
||||
return await HandleResponse<PayoutData[]>(response);
|
||||
}
|
||||
public async Task<PayoutData> CreatePayout(string pullPaymentId, CreatePayoutRequest payoutRequest, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/pull-payments/{HttpUtility.UrlEncode(pullPaymentId)}/payouts", bodyPayload: payoutRequest, method: HttpMethod.Post), cancellationToken);
|
||||
return await HandleResponse<PayoutData>(response);
|
||||
}
|
||||
|
||||
public virtual async Task ArchivePullPayment(string storeId, string pullPaymentId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
await SendHttpRequest($"api/v1/stores/{HttpUtility.UrlEncode(storeId)}/pull-payments/{HttpUtility.UrlEncode(pullPaymentId)}", null, HttpMethod.Delete, cancellationToken);
|
||||
}
|
||||
|
||||
public virtual async Task<PayoutData[]> GetPayouts(string pullPaymentId, bool includeCancelled = false, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var query = new Dictionary<string, object> { { "includeCancelled", includeCancelled } };
|
||||
return await SendHttpRequest<PayoutData[]>($"api/v1/pull-payments/{HttpUtility.UrlEncode(pullPaymentId)}/payouts", query, HttpMethod.Get, cancellationToken);
|
||||
}
|
||||
|
||||
public virtual async Task<PayoutData[]> GetStorePayouts(string storeId, bool includeCancelled = false, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var query = new Dictionary<string, object> { { "includeCancelled", includeCancelled } };
|
||||
return await SendHttpRequest<PayoutData[]>($"api/v1/stores/{storeId}/payouts", queryPayload: query, method: HttpMethod.Get, cancellationToken);
|
||||
}
|
||||
|
||||
public virtual async Task<PayoutData> CreatePayout(string pullPaymentId, CreatePayoutRequest payoutRequest, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await SendHttpRequest<PayoutData>($"api/v1/pull-payments/{HttpUtility.UrlEncode(pullPaymentId)}/payouts", bodyPayload: payoutRequest, HttpMethod.Post, cancellationToken);
|
||||
}
|
||||
|
||||
public virtual async Task<PayoutData> GetPullPaymentPayout(string pullPaymentId, string payoutId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await SendHttpRequest<PayoutData>($"api/v1/pull-payments/{HttpUtility.UrlEncode(pullPaymentId)}/payouts/{payoutId}", null, HttpMethod.Get, cancellationToken);
|
||||
}
|
||||
|
||||
public virtual async Task<PayoutData> GetStorePayout(string storeId, string payoutId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await SendHttpRequest<PayoutData>($"api/v1/stores/{storeId}/payouts/{payoutId}", null, HttpMethod.Get, cancellationToken);
|
||||
}
|
||||
|
||||
public virtual async Task<PayoutData> CreatePayout(string storeId, CreatePayoutThroughStoreRequest payoutRequest, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await SendHttpRequest<PayoutData>($"api/v1/stores/{storeId}/payouts", bodyPayload: payoutRequest, method: HttpMethod.Post, cancellationToken);
|
||||
}
|
||||
|
||||
public virtual async Task CancelPayout(string storeId, string payoutId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
await SendHttpRequest($"api/v1/stores/{HttpUtility.UrlEncode(storeId)}/payouts/{HttpUtility.UrlEncode(payoutId)}", null, HttpMethod.Delete, cancellationToken);
|
||||
}
|
||||
|
||||
public virtual async Task<PayoutData> ApprovePayout(string storeId, string payoutId, ApprovePayoutRequest request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await SendHttpRequest<PayoutData>($"api/v1/stores/{HttpUtility.UrlEncode(storeId)}/payouts/{HttpUtility.UrlEncode(payoutId)}", request, HttpMethod.Post, cancellationToken);
|
||||
}
|
||||
|
||||
public virtual async Task MarkPayoutPaid(string storeId, string payoutId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
await SendHttpRequest($"api/v1/stores/{HttpUtility.UrlEncode(storeId)}/payouts/{HttpUtility.UrlEncode(payoutId)}/mark-paid", null, HttpMethod.Post, cancellationToken);
|
||||
}
|
||||
|
||||
public virtual async Task MarkPayout(string storeId, string payoutId, MarkPayoutRequest request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
await SendHttpRequest($"api/v1/stores/{HttpUtility.UrlEncode(storeId)}/payouts/{HttpUtility.UrlEncode(payoutId)}/mark", request, HttpMethod.Post, cancellationToken);
|
||||
}
|
||||
|
||||
public virtual async Task<PullPaymentLNURL> GetPullPaymentLNURL(string pullPaymentId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await SendHttpRequest<PullPaymentLNURL>($"api/v1/pull-payments/{HttpUtility.UrlEncode(pullPaymentId)}/lnurl", null, HttpMethod.Get, cancellationToken);
|
||||
public async Task CancelPayout(string storeId, string payoutId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{HttpUtility.UrlEncode(storeId)}/payouts/{HttpUtility.UrlEncode(payoutId)}", method: HttpMethod.Delete), cancellationToken);
|
||||
await HandleResponse(response);
|
||||
}
|
||||
public async Task<PayoutData> ApprovePayout(string storeId, string payoutId, ApprovePayoutRequest request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{HttpUtility.UrlEncode(storeId)}/payouts/{HttpUtility.UrlEncode(payoutId)}", bodyPayload: request, method: HttpMethod.Post), cancellationToken);
|
||||
return await HandleResponse<PayoutData>(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
|
||||
namespace BTCPayServer.Client;
|
||||
|
||||
public partial class BTCPayServerClient
|
||||
{
|
||||
public virtual async Task<ServerEmailSettingsData> GetServerEmailSettings(CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<ServerEmailSettingsData>("api/v1/server/email", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<bool> UpdateServerEmailSettings(ServerEmailSettingsData request, CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<bool>("api/v1/server/email", request, HttpMethod.Put, token);
|
||||
}
|
||||
}
|
@ -1,20 +1,15 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
|
||||
namespace BTCPayServer.Client;
|
||||
|
||||
public partial class BTCPayServerClient
|
||||
namespace BTCPayServer.Client
|
||||
{
|
||||
public virtual async Task<ServerInfoData> GetServerInfo(CancellationToken token = default)
|
||||
public partial class BTCPayServerClient
|
||||
{
|
||||
return await SendHttpRequest<ServerInfoData>("api/v1/server/info", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<List<RoleData>> GetServerRoles(CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<List<RoleData>>("api/v1/server/roles", null, HttpMethod.Get, token);
|
||||
public virtual async Task<ServerInfoData> GetServerInfo(CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest("api/v1/server/info"), token);
|
||||
return await HandleResponse<ServerInfoData>(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,24 +0,0 @@
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
|
||||
namespace BTCPayServer.Client;
|
||||
|
||||
public partial class BTCPayServerClient
|
||||
{
|
||||
public virtual async Task<EmailSettingsData> GetStoreEmailSettings(string storeId, CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<EmailSettingsData>($"api/v1/stores/{storeId}/email", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<EmailSettingsData> UpdateStoreEmailSettings(string storeId, EmailSettingsData request, CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<EmailSettingsData>($"api/v1/stores/{storeId}/email", request, method: HttpMethod.Put, token);
|
||||
}
|
||||
|
||||
public virtual async Task SendEmail(string storeId, SendEmailRequest request, CancellationToken token = default)
|
||||
{
|
||||
await SendHttpRequest($"api/v1/stores/{storeId}/email/send", request, HttpMethod.Post, token);
|
||||
}
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
|
||||
namespace BTCPayServer.Client;
|
||||
|
||||
public partial class BTCPayServerClient
|
||||
{
|
||||
public virtual async Task<GenericPaymentMethodData> UpdateStorePaymentMethod(string storeId, string paymentMethodId, UpdatePaymentMethodRequest request, CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<GenericPaymentMethodData>($"api/v1/stores/{storeId}/payment-methods/{paymentMethodId}", request, HttpMethod.Put, token);
|
||||
}
|
||||
|
||||
public virtual async Task RemoveStorePaymentMethod(string storeId, string paymentMethodId)
|
||||
{
|
||||
await SendHttpRequest($"api/v1/stores/{storeId}/payment-methods/{paymentMethodId}", null, HttpMethod.Delete, CancellationToken.None);
|
||||
}
|
||||
|
||||
public virtual async Task<GenericPaymentMethodData> GetStorePaymentMethod(string storeId, string paymentMethodId, bool? includeConfig = null, CancellationToken token = default)
|
||||
{
|
||||
var query = new Dictionary<string, object>();
|
||||
if (includeConfig != null)
|
||||
{
|
||||
query.Add(nameof(includeConfig), includeConfig);
|
||||
}
|
||||
return await SendHttpRequest<GenericPaymentMethodData>($"api/v1/stores/{storeId}/payment-methods/{paymentMethodId}", query, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<GenericPaymentMethodData[]> GetStorePaymentMethods(string storeId, bool? onlyEnabled = null, bool? includeConfig = null, CancellationToken token = default)
|
||||
{
|
||||
var query = new Dictionary<string, object>();
|
||||
if (onlyEnabled != null)
|
||||
{
|
||||
query.Add(nameof(onlyEnabled), onlyEnabled);
|
||||
}
|
||||
if (includeConfig != null)
|
||||
{
|
||||
query.Add(nameof(includeConfig), includeConfig);
|
||||
}
|
||||
|
||||
return await SendHttpRequest<GenericPaymentMethodData[]>($"api/v1/stores/{storeId}/payment-methods", query, HttpMethod.Get, token);
|
||||
}
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
|
||||
namespace BTCPayServer.Client;
|
||||
|
||||
public partial class BTCPayServerClient
|
||||
{
|
||||
public virtual async Task<IEnumerable<PayoutProcessorData>> GetPayoutProcessors(string storeId, CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<IEnumerable<PayoutProcessorData>>($"api/v1/stores/{storeId}/payout-processors", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task RemovePayoutProcessor(string storeId, string processor, string paymentMethod, CancellationToken token = default)
|
||||
{
|
||||
await SendHttpRequest($"api/v1/stores/{storeId}/payout-processors/{processor}/{paymentMethod}", null, HttpMethod.Delete, token);
|
||||
}
|
||||
|
||||
public virtual async Task<IEnumerable<LightningAutomatedPayoutSettings>> GetStoreLightningAutomatedPayoutProcessors(string storeId, string? payoutMethodId = null, CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<IEnumerable<LightningAutomatedPayoutSettings>>($"api/v1/stores/{storeId}/payout-processors/LightningAutomatedPayoutSenderFactory{(payoutMethodId is null ? string.Empty : $"/{payoutMethodId}")}", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<LightningAutomatedPayoutSettings> UpdateStoreLightningAutomatedPayoutProcessors(string storeId, string payoutMethodId, LightningAutomatedPayoutSettings request, CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<LightningAutomatedPayoutSettings>($"api/v1/stores/{storeId}/payout-processors/LightningAutomatedPayoutSenderFactory/{payoutMethodId}", request, HttpMethod.Put, token);
|
||||
}
|
||||
|
||||
public virtual async Task<OnChainAutomatedPayoutSettings> UpdateStoreOnChainAutomatedPayoutProcessors(string storeId, string paymentMethod, OnChainAutomatedPayoutSettings request, CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<OnChainAutomatedPayoutSettings>($"api/v1/stores/{storeId}/payout-processors/OnChainAutomatedPayoutSenderFactory/{paymentMethod}", request, HttpMethod.Put, token);
|
||||
}
|
||||
|
||||
public virtual async Task<IEnumerable<OnChainAutomatedPayoutSettings>> GetStoreOnChainAutomatedPayoutProcessors(string storeId, string? paymentMethod = null, CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<IEnumerable<OnChainAutomatedPayoutSettings>>($"api/v1/stores/{storeId}/payout-processors/OnChainAutomatedPayoutSenderFactory{(paymentMethod is null ? string.Empty : $"/{paymentMethod}")}", null, HttpMethod.Get, token);
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
|
||||
namespace BTCPayServer.Client;
|
||||
|
||||
public partial class BTCPayServerClient
|
||||
{
|
||||
public virtual async Task<StoreRateConfiguration> GetStoreRateConfiguration(string storeId, CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<StoreRateConfiguration>($"api/v1/stores/{storeId}/rates/configuration", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<List<RateSource>> GetRateSources(CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<List<RateSource>>("misc/rate-sources", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<StoreRateConfiguration> UpdateStoreRateConfiguration(string storeId, StoreRateConfiguration request, CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<StoreRateConfiguration>($"api/v1/stores/{storeId}/rates/configuration", request, HttpMethod.Put, token);
|
||||
}
|
||||
|
||||
public virtual async Task<List<StoreRateResult>> PreviewUpdateStoreRateConfiguration(string storeId, StoreRateConfiguration request, string[] currencyPair = null, CancellationToken token = default)
|
||||
{
|
||||
var queryPayload = currencyPair == null ? null : new Dictionary<string, object> { { "currencyPair", currencyPair } };
|
||||
return await SendHttpRequest<StoreRateConfiguration, List<StoreRateResult>>($"api/v1/stores/{storeId}/rates/configuration/preview", queryPayload, request, HttpMethod.Post, token);
|
||||
}
|
||||
|
||||
public virtual async Task<List<StoreRateResult>> GetStoreRates(string storeId, string[] currencyPair = null, CancellationToken token = default)
|
||||
{
|
||||
var queryPayload = currencyPair == null ? null : new Dictionary<string, object> { { "currencyPair", currencyPair } };
|
||||
return await SendHttpRequest<List<StoreRateResult>>($"api/v1/stores/{storeId}/rates", queryPayload, HttpMethod.Get, token);
|
||||
}
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
|
||||
namespace BTCPayServer.Client;
|
||||
|
||||
public partial class BTCPayServerClient
|
||||
{
|
||||
public virtual async Task<List<RoleData>> GetStoreRoles(string storeId, CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<List<RoleData>>($"api/v1/stores/{storeId}/roles", null, HttpMethod.Get,token);
|
||||
}
|
||||
|
||||
public virtual async Task<IEnumerable<StoreUserData>> GetStoreUsers(string storeId, CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<IEnumerable<StoreUserData>>($"api/v1/stores/{storeId}/users", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task RemoveStoreUser(string storeId, string userId, CancellationToken token = default)
|
||||
{
|
||||
await SendHttpRequest($"api/v1/stores/{storeId}/users/{userId}", null, HttpMethod.Delete, token);
|
||||
}
|
||||
|
||||
public virtual async Task AddStoreUser(string storeId, StoreUserData request, CancellationToken token = default)
|
||||
{
|
||||
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||
await SendHttpRequest<StoreUserData>($"api/v1/stores/{storeId}/users", request, HttpMethod.Post, token);
|
||||
}
|
||||
|
||||
public virtual async Task UpdateStoreUser(string storeId, string userId, StoreUserData request, CancellationToken token = default)
|
||||
{
|
||||
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||
await SendHttpRequest<StoreUserData>($"api/v1/stores/{storeId}/users/{userId}", request, HttpMethod.Put, token);
|
||||
}
|
||||
}
|
@ -5,45 +5,47 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
|
||||
namespace BTCPayServer.Client;
|
||||
|
||||
public partial class BTCPayServerClient
|
||||
namespace BTCPayServer.Client
|
||||
{
|
||||
public virtual async Task<IEnumerable<StoreData>> GetStores(CancellationToken token = default)
|
||||
public partial class BTCPayServerClient
|
||||
{
|
||||
return await SendHttpRequest<IEnumerable<StoreData>>("api/v1/stores", null, HttpMethod.Get, token);
|
||||
}
|
||||
public virtual async Task<IEnumerable<StoreData>> GetStores(CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest("api/v1/stores"), token);
|
||||
return await HandleResponse<IEnumerable<StoreData>>(response);
|
||||
}
|
||||
|
||||
public virtual async Task<StoreData> GetStore(string storeId, CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<StoreData>($"api/v1/stores/{storeId}", null, HttpMethod.Get, token);
|
||||
}
|
||||
public virtual async Task<StoreData> GetStore(string storeId, CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}"), token);
|
||||
return await HandleResponse<StoreData>(response);
|
||||
}
|
||||
|
||||
public virtual async Task RemoveStore(string storeId, CancellationToken token = default)
|
||||
{
|
||||
await SendHttpRequest($"api/v1/stores/{storeId}", null, HttpMethod.Delete, token);
|
||||
}
|
||||
public virtual async Task RemoveStore(string storeId, CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}", method: HttpMethod.Delete), token);
|
||||
await HandleResponse(response);
|
||||
}
|
||||
|
||||
public virtual async Task<StoreData> CreateStore(CreateStoreRequest request, CancellationToken token = default)
|
||||
{
|
||||
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||
return await SendHttpRequest<StoreData>("api/v1/stores", request, HttpMethod.Post, token);
|
||||
}
|
||||
public virtual async Task<StoreData> CreateStore(CreateStoreRequest request, CancellationToken token = default)
|
||||
{
|
||||
if (request == null)
|
||||
throw new ArgumentNullException(nameof(request));
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest("api/v1/stores", bodyPayload: request, method: HttpMethod.Post), token);
|
||||
return await HandleResponse<StoreData>(response);
|
||||
}
|
||||
|
||||
public virtual async Task<StoreData> UpdateStore(string storeId, UpdateStoreRequest request, CancellationToken token = default)
|
||||
{
|
||||
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||
if (storeId == null) throw new ArgumentNullException(nameof(storeId));
|
||||
return await SendHttpRequest<StoreData>($"api/v1/stores/{storeId}", request, HttpMethod.Put, token);
|
||||
}
|
||||
public virtual async Task<StoreData> UpdateStore(string storeId, UpdateStoreRequest request, CancellationToken token = default)
|
||||
{
|
||||
if (request == null)
|
||||
throw new ArgumentNullException(nameof(request));
|
||||
if (storeId == null)
|
||||
throw new ArgumentNullException(nameof(storeId));
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}", bodyPayload: request, method: HttpMethod.Put), token);
|
||||
return await HandleResponse<StoreData>(response);
|
||||
}
|
||||
|
||||
public virtual async Task<StoreData> UploadStoreLogo(string storeId, string filePath, string mimeType, CancellationToken token = default)
|
||||
{
|
||||
return await UploadFileRequest<StoreData>($"api/v1/stores/{storeId}/logo", filePath, mimeType, "file", HttpMethod.Post, token);
|
||||
}
|
||||
|
||||
public virtual async Task DeleteStoreLogo(string storeId, CancellationToken token = default)
|
||||
{
|
||||
await SendHttpRequest($"api/v1/stores/{storeId}/logo", null, HttpMethod.Delete, token);
|
||||
}
|
||||
}
|
||||
|
@ -1,71 +1,23 @@
|
||||
#nullable enable
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
|
||||
namespace BTCPayServer.Client;
|
||||
|
||||
public partial class BTCPayServerClient
|
||||
namespace BTCPayServer.Client
|
||||
{
|
||||
public virtual async Task<ApplicationUserData> GetCurrentUser(CancellationToken token = default)
|
||||
public partial class BTCPayServerClient
|
||||
{
|
||||
return await SendHttpRequest<ApplicationUserData>("api/v1/users/me", null, HttpMethod.Get, token);
|
||||
}
|
||||
public virtual async Task<ApplicationUserData> GetCurrentUser(CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest("api/v1/users/me"), token);
|
||||
return await HandleResponse<ApplicationUserData>(response);
|
||||
}
|
||||
|
||||
public virtual async Task<ApplicationUserData> UpdateCurrentUser(UpdateApplicationUserRequest request, CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<ApplicationUserData>("api/v1/users/me", request, HttpMethod.Put, token);
|
||||
}
|
||||
|
||||
public virtual async Task<ApplicationUserData> UploadCurrentUserProfilePicture(string filePath, string mimeType, CancellationToken token = default)
|
||||
{
|
||||
return await UploadFileRequest<ApplicationUserData>("api/v1/users/me/picture", filePath, mimeType, "file", HttpMethod.Post, token);
|
||||
}
|
||||
|
||||
public virtual async Task DeleteCurrentUserProfilePicture(CancellationToken token = default)
|
||||
{
|
||||
await SendHttpRequest("api/v1/users/me/picture", null, HttpMethod.Delete, token);
|
||||
}
|
||||
|
||||
public virtual async Task<ApplicationUserData> CreateUser(CreateApplicationUserRequest request, CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<ApplicationUserData>("api/v1/users", request, HttpMethod.Post, token);
|
||||
}
|
||||
|
||||
public virtual async Task DeleteUser(string userId, CancellationToken token = default)
|
||||
{
|
||||
await SendHttpRequest($"api/v1/users/{userId}", null, HttpMethod.Delete, token);
|
||||
}
|
||||
|
||||
public virtual async Task<ApplicationUserData> GetUserByIdOrEmail(string idOrEmail, CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<ApplicationUserData>($"api/v1/users/{idOrEmail}", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<bool> LockUser(string idOrEmail, bool locked, CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/users/{idOrEmail}/lock", null,
|
||||
new LockUserRequest { Locked = locked }, HttpMethod.Post), token);
|
||||
await HandleResponse(response);
|
||||
return response.IsSuccessStatusCode;
|
||||
}
|
||||
|
||||
public virtual async Task<bool> ApproveUser(string idOrEmail, bool approved, CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/users/{idOrEmail}/approve", null,
|
||||
new ApproveUserRequest { Approved = approved }, HttpMethod.Post), token);
|
||||
await HandleResponse(response);
|
||||
return response.IsSuccessStatusCode;
|
||||
}
|
||||
|
||||
public virtual async Task<ApplicationUserData[]> GetUsers(CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<ApplicationUserData[]>("api/v1/users/", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task DeleteCurrentUser(CancellationToken token = default)
|
||||
{
|
||||
await DeleteUser("me", token);
|
||||
public virtual async Task<ApplicationUserData> CreateUser(CreateApplicationUserRequest request,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest("api/v1/users", null, request, HttpMethod.Post), token);
|
||||
return await HandleResponse<ApplicationUserData>(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,58 +0,0 @@
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
|
||||
namespace BTCPayServer.Client;
|
||||
|
||||
public partial class BTCPayServerClient
|
||||
{
|
||||
public virtual async Task<StoreWebhookData> CreateWebhook(string storeId, CreateStoreWebhookRequest create, CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<StoreWebhookData>($"api/v1/stores/{storeId}/webhooks", create, HttpMethod.Post, token);
|
||||
}
|
||||
|
||||
public virtual async Task<StoreWebhookData> GetWebhook(string storeId, string webhookId, CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/webhooks/{webhookId}"), token);
|
||||
return response.StatusCode == System.Net.HttpStatusCode.NotFound ? null : await HandleResponse<StoreWebhookData>(response);
|
||||
}
|
||||
|
||||
public virtual async Task<StoreWebhookData> UpdateWebhook(string storeId, string webhookId, UpdateStoreWebhookRequest update, CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<StoreWebhookData>($"api/v1/stores/{storeId}/webhooks/{webhookId}", update, HttpMethod.Put, token);
|
||||
}
|
||||
|
||||
public virtual async Task<bool> DeleteWebhook(string storeId, string webhookId, CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/webhooks/{webhookId}", method: HttpMethod.Delete), token);
|
||||
return response.IsSuccessStatusCode;
|
||||
}
|
||||
|
||||
public virtual async Task<StoreWebhookData[]> GetWebhooks(string storeId, CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<StoreWebhookData[]>($"api/v1/stores/{storeId}/webhooks", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<WebhookDeliveryData[]> GetWebhookDeliveries(string storeId, string webhookId, CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<WebhookDeliveryData[]>($"api/v1/stores/{storeId}/webhooks/{webhookId}/deliveries", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<WebhookDeliveryData> GetWebhookDelivery(string storeId, string webhookId, string deliveryId, CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/webhooks/{webhookId}/deliveries/{deliveryId}"), token);
|
||||
return response.StatusCode == System.Net.HttpStatusCode.NotFound ? null : await HandleResponse<WebhookDeliveryData>(response);
|
||||
}
|
||||
|
||||
public virtual async Task<string> RedeliverWebhook(string storeId, string webhookId, string deliveryId, CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<string>($"api/v1/stores/{storeId}/webhooks/{webhookId}/deliveries/{deliveryId}/redeliver", null, HttpMethod.Post, token);
|
||||
}
|
||||
|
||||
public virtual async Task<WebhookEvent> GetWebhookDeliveryRequest(string storeId, string webhookId, string deliveryId, CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/webhooks/{webhookId}/deliveries/{deliveryId}/request"), token);
|
||||
return response.StatusCode == System.Net.HttpStatusCode.NotFound ? null : await HandleResponse<WebhookEvent>(response);
|
||||
}
|
||||
}
|
@ -1,201 +1,139 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BTCPayServer.Client;
|
||||
|
||||
public partial class BTCPayServerClient
|
||||
namespace BTCPayServer.Client
|
||||
{
|
||||
private readonly string _apiKey;
|
||||
private readonly Uri _btcpayHost;
|
||||
private readonly string _username;
|
||||
private readonly string _password;
|
||||
protected readonly HttpClient _httpClient;
|
||||
public Uri Host => _btcpayHost;
|
||||
|
||||
public string APIKey => _apiKey;
|
||||
|
||||
public BTCPayServerClient(Uri btcpayHost, HttpClient httpClient = null)
|
||||
public partial class BTCPayServerClient
|
||||
{
|
||||
if (btcpayHost == null) throw new ArgumentNullException(nameof(btcpayHost));
|
||||
_btcpayHost = btcpayHost;
|
||||
_httpClient = httpClient ?? new HttpClient();
|
||||
}
|
||||
private readonly string _apiKey;
|
||||
private readonly Uri _btcpayHost;
|
||||
private readonly string _username;
|
||||
private readonly string _password;
|
||||
private readonly HttpClient _httpClient;
|
||||
|
||||
public BTCPayServerClient(Uri btcpayHost, string APIKey, HttpClient httpClient = null)
|
||||
{
|
||||
_apiKey = APIKey;
|
||||
_btcpayHost = btcpayHost;
|
||||
_httpClient = httpClient ?? new HttpClient();
|
||||
}
|
||||
public Uri Host => _btcpayHost;
|
||||
|
||||
public BTCPayServerClient(Uri btcpayHost, string username, string password, HttpClient httpClient = null)
|
||||
{
|
||||
_apiKey = APIKey;
|
||||
_btcpayHost = btcpayHost;
|
||||
_username = username;
|
||||
_password = password;
|
||||
_httpClient = httpClient ?? new HttpClient();
|
||||
}
|
||||
public string APIKey => _apiKey;
|
||||
|
||||
protected async Task HandleResponse(HttpResponseMessage message)
|
||||
{
|
||||
if (!message.IsSuccessStatusCode && message.Content?.Headers?.ContentType?.MediaType?.StartsWith("application/json", StringComparison.OrdinalIgnoreCase) is true)
|
||||
public BTCPayServerClient(Uri btcpayHost, HttpClient httpClient = null)
|
||||
{
|
||||
if (btcpayHost == null)
|
||||
throw new ArgumentNullException(nameof(btcpayHost));
|
||||
_btcpayHost = btcpayHost;
|
||||
_httpClient = httpClient ?? new HttpClient();
|
||||
}
|
||||
public BTCPayServerClient(Uri btcpayHost, string APIKey, HttpClient httpClient = null)
|
||||
{
|
||||
_apiKey = APIKey;
|
||||
_btcpayHost = btcpayHost;
|
||||
_httpClient = httpClient ?? new HttpClient();
|
||||
}
|
||||
|
||||
public BTCPayServerClient(Uri btcpayHost, string username, string password, HttpClient httpClient = null)
|
||||
{
|
||||
_apiKey = APIKey;
|
||||
_btcpayHost = btcpayHost;
|
||||
_username = username;
|
||||
_password = password;
|
||||
_httpClient = httpClient ?? new HttpClient();
|
||||
}
|
||||
|
||||
protected async Task HandleResponse(HttpResponseMessage message)
|
||||
{
|
||||
if (message.StatusCode == System.Net.HttpStatusCode.UnprocessableEntity)
|
||||
{
|
||||
var aa = await message.Content.ReadAsStringAsync();
|
||||
var err = JsonConvert.DeserializeObject<Models.GreenfieldValidationError[]>(aa);
|
||||
throw new GreenfieldValidationException(err);
|
||||
var err = JsonConvert.DeserializeObject<Models.GreenfieldValidationError[]>(await message.Content.ReadAsStringAsync());
|
||||
;
|
||||
throw new GreenFieldValidationException(err);
|
||||
}
|
||||
if (message.StatusCode == System.Net.HttpStatusCode.Forbidden)
|
||||
else if (message.StatusCode == System.Net.HttpStatusCode.BadRequest)
|
||||
{
|
||||
var err = JsonConvert.DeserializeObject<Models.GreenfieldPermissionAPIError>(await message.Content.ReadAsStringAsync());
|
||||
throw new GreenfieldAPIException((int)message.StatusCode, err);
|
||||
var err = JsonConvert.DeserializeObject<Models.GreenfieldAPIError>(await message.Content.ReadAsStringAsync());
|
||||
throw new GreenFieldAPIException(err);
|
||||
}
|
||||
|
||||
message.EnsureSuccessStatusCode();
|
||||
}
|
||||
|
||||
protected async Task<T> HandleResponse<T>(HttpResponseMessage message)
|
||||
{
|
||||
await HandleResponse(message);
|
||||
return JsonConvert.DeserializeObject<T>(await message.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
protected virtual HttpRequestMessage CreateHttpRequest(string path,
|
||||
Dictionary<string, object> queryPayload = null,
|
||||
HttpMethod method = null)
|
||||
{
|
||||
UriBuilder uriBuilder = new UriBuilder(_btcpayHost) { Path = path };
|
||||
if (queryPayload != null && queryPayload.Any())
|
||||
{
|
||||
AppendPayloadToQuery(uriBuilder, queryPayload);
|
||||
}
|
||||
|
||||
var httpRequest = new HttpRequestMessage(method ?? HttpMethod.Get, uriBuilder.Uri);
|
||||
if (_apiKey != null)
|
||||
httpRequest.Headers.Authorization = new AuthenticationHeaderValue("token", _apiKey);
|
||||
else if (!string.IsNullOrEmpty(_username))
|
||||
{
|
||||
httpRequest.Headers.Authorization = new AuthenticationHeaderValue("Basic", System.Convert.ToBase64String(Encoding.ASCII.GetBytes(_username + ":" + _password)));
|
||||
}
|
||||
|
||||
|
||||
return httpRequest;
|
||||
}
|
||||
|
||||
protected virtual HttpRequestMessage CreateHttpRequest<T>(string path,
|
||||
Dictionary<string, object> queryPayload = null,
|
||||
T bodyPayload = default, HttpMethod method = null)
|
||||
{
|
||||
var request = CreateHttpRequest(path, queryPayload, method);
|
||||
if (typeof(T).IsPrimitive || !EqualityComparer<T>.Default.Equals(bodyPayload, default(T)))
|
||||
{
|
||||
request.Content = new StringContent(JsonConvert.SerializeObject(bodyPayload), Encoding.UTF8, "application/json");
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
public static void AppendPayloadToQuery(UriBuilder uri, KeyValuePair<string, object> keyValuePair)
|
||||
{
|
||||
if (uri.Query.Length > 1)
|
||||
uri.Query += "&";
|
||||
|
||||
UriBuilder uriBuilder = uri;
|
||||
if (!(keyValuePair.Value is string) &&
|
||||
keyValuePair.Value.GetType().GetInterfaces().Contains((typeof(IEnumerable))))
|
||||
{
|
||||
foreach (var item in (IEnumerable)keyValuePair.Value)
|
||||
{
|
||||
uriBuilder.Query = uriBuilder.Query + Uri.EscapeDataString(keyValuePair.Key) + "=" +
|
||||
Uri.EscapeDataString(item.ToString()) + "&";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var err = JsonConvert.DeserializeObject<Models.GreenfieldAPIError>(await message.Content.ReadAsStringAsync());
|
||||
if (err.Code != null)
|
||||
throw new GreenfieldAPIException((int)message.StatusCode, err);
|
||||
}
|
||||
}
|
||||
message.EnsureSuccessStatusCode();
|
||||
}
|
||||
|
||||
protected virtual async Task<T> HandleResponse<T>(HttpResponseMessage message)
|
||||
{
|
||||
await HandleResponse(message);
|
||||
var str = await message.Content.ReadAsStringAsync();
|
||||
return JsonConvert.DeserializeObject<T>(str);
|
||||
}
|
||||
|
||||
public virtual async Task SendHttpRequest(string path,
|
||||
Dictionary<string, object> queryPayload = null,
|
||||
HttpMethod method = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var resp = await _httpClient.SendAsync(CreateHttpRequest(path, queryPayload, method), cancellationToken);
|
||||
await HandleResponse(resp);
|
||||
}
|
||||
|
||||
public virtual async Task<T> SendHttpRequest<T>(string path,
|
||||
Dictionary<string, object> queryPayload = null,
|
||||
HttpMethod method = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var resp = await _httpClient.SendAsync(CreateHttpRequest(path, queryPayload, method), cancellationToken);
|
||||
return await HandleResponse<T>(resp);
|
||||
}
|
||||
|
||||
public virtual async Task SendHttpRequest(string path,
|
||||
object bodyPayload = null,
|
||||
HttpMethod method = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var resp = await _httpClient.SendAsync(CreateHttpRequest(path: path, bodyPayload: bodyPayload, method: method), cancellationToken);
|
||||
await HandleResponse(resp);
|
||||
}
|
||||
|
||||
protected virtual async Task<T> SendHttpRequest<T>(string path,
|
||||
object bodyPayload = null,
|
||||
HttpMethod method = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var resp = await _httpClient.SendAsync(CreateHttpRequest(path: path, bodyPayload: bodyPayload, method: method), cancellationToken);
|
||||
return await HandleResponse<T>(resp);
|
||||
}
|
||||
|
||||
protected virtual async Task<TRes> SendHttpRequest<TReq, TRes>(string path,
|
||||
Dictionary<string, object> queryPayload = null,
|
||||
TReq bodyPayload = default, HttpMethod method = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var resp = await _httpClient.SendAsync(CreateHttpRequest(path: path, bodyPayload: bodyPayload, queryPayload: queryPayload, method: method), cancellationToken);
|
||||
return await HandleResponse<TRes>(resp);
|
||||
}
|
||||
|
||||
protected virtual HttpRequestMessage CreateHttpRequest(string path,
|
||||
Dictionary<string, object> queryPayload = null,
|
||||
HttpMethod method = null)
|
||||
{
|
||||
var uriBuilder = new UriBuilder(_btcpayHost);
|
||||
uriBuilder.Path += (uriBuilder.Path.EndsWith("/") || path.StartsWith("/") ? "" : "/") + path;
|
||||
if (queryPayload != null && queryPayload.Any())
|
||||
{
|
||||
AppendPayloadToQuery(uriBuilder, queryPayload);
|
||||
}
|
||||
|
||||
var httpRequest = new HttpRequestMessage(method ?? HttpMethod.Get, uriBuilder.Uri);
|
||||
if (_apiKey != null)
|
||||
httpRequest.Headers.Authorization = new AuthenticationHeaderValue("token", _apiKey);
|
||||
else if (!string.IsNullOrEmpty(_username))
|
||||
{
|
||||
httpRequest.Headers.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes(_username + ":" + _password)));
|
||||
}
|
||||
|
||||
return httpRequest;
|
||||
}
|
||||
|
||||
protected virtual HttpRequestMessage CreateHttpRequest<T>(string path,
|
||||
Dictionary<string, object> queryPayload = null,
|
||||
T bodyPayload = default, HttpMethod method = null)
|
||||
{
|
||||
var request = CreateHttpRequest(path, queryPayload, method);
|
||||
if (typeof(T).IsPrimitive || !EqualityComparer<T>.Default.Equals(bodyPayload, default(T)))
|
||||
{
|
||||
request.Content = new StringContent(JsonConvert.SerializeObject(bodyPayload), Encoding.UTF8, "application/json");
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
protected virtual async Task<T> UploadFileRequest<T>(string apiPath, string filePath, string mimeType, string formFieldName, HttpMethod method = null, CancellationToken token = default)
|
||||
{
|
||||
using MultipartFormDataContent multipartContent = new();
|
||||
using var fileContent = new StreamContent(File.OpenRead(filePath));
|
||||
var fileName = Path.GetFileName(filePath);
|
||||
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse(mimeType);
|
||||
multipartContent.Add(fileContent, formFieldName, fileName);
|
||||
var req = CreateHttpRequest(apiPath, null, method ?? HttpMethod.Post);
|
||||
req.Content = multipartContent;
|
||||
using var resp = await _httpClient.SendAsync(req, token);
|
||||
return await HandleResponse<T>(resp);
|
||||
}
|
||||
|
||||
public static void AppendPayloadToQuery(UriBuilder uri, KeyValuePair<string, object> keyValuePair)
|
||||
{
|
||||
if (uri.Query.Length > 1)
|
||||
uri.Query += "&";
|
||||
|
||||
UriBuilder uriBuilder = uri;
|
||||
if (!(keyValuePair.Value is string) &&
|
||||
keyValuePair.Value.GetType().GetInterfaces().Contains((typeof(IEnumerable))))
|
||||
{
|
||||
foreach (var item in (IEnumerable)keyValuePair.Value)
|
||||
{
|
||||
uriBuilder.Query = uriBuilder.Query + Uri.EscapeDataString(keyValuePair.Key) + "=" +
|
||||
Uri.EscapeDataString(item.ToString()) + "&";
|
||||
Uri.EscapeDataString(keyValuePair.Value.ToString()) + "&";
|
||||
}
|
||||
uri.Query = uri.Query.Trim('&');
|
||||
}
|
||||
else
|
||||
{
|
||||
uriBuilder.Query = uriBuilder.Query + Uri.EscapeDataString(keyValuePair.Key) + "=" +
|
||||
Uri.EscapeDataString(keyValuePair.Value.ToString()) + "&";
|
||||
}
|
||||
uri.Query = uri.Query.Trim('&');
|
||||
}
|
||||
|
||||
public static void AppendPayloadToQuery(UriBuilder uri, Dictionary<string, object> payload)
|
||||
{
|
||||
if (uri.Query.Length > 1)
|
||||
uri.Query += "&";
|
||||
foreach (KeyValuePair<string, object> keyValuePair in payload)
|
||||
public static void AppendPayloadToQuery(UriBuilder uri, Dictionary<string, object> payload)
|
||||
{
|
||||
AppendPayloadToQuery(uri, keyValuePair);
|
||||
if (uri.Query.Length > 1)
|
||||
uri.Query += "&";
|
||||
foreach (KeyValuePair<string, object> keyValuePair in payload)
|
||||
{
|
||||
AppendPayloadToQuery(uri, keyValuePair);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace BTCPayServer.Client;
|
||||
|
||||
public class GreenfieldAPIException : Exception
|
||||
namespace BTCPayServer.Client
|
||||
{
|
||||
public GreenfieldAPIException(int httpCode, Models.GreenfieldAPIError error) : base(error.Message)
|
||||
public class GreenFieldAPIException : Exception
|
||||
{
|
||||
if (error == null) throw new ArgumentNullException(nameof(error));
|
||||
HttpCode = httpCode;
|
||||
APIError = error;
|
||||
public GreenFieldAPIException(Models.GreenfieldAPIError error) : base(error.Message)
|
||||
{
|
||||
if (error == null)
|
||||
throw new ArgumentNullException(nameof(error));
|
||||
APIError = error;
|
||||
}
|
||||
public Models.GreenfieldAPIError APIError { get; }
|
||||
}
|
||||
public Models.GreenfieldAPIError APIError { get; }
|
||||
public int HttpCode { get; set; }
|
||||
}
|
||||
|
@ -2,25 +2,27 @@ using System;
|
||||
using System.Text;
|
||||
using BTCPayServer.Client.Models;
|
||||
|
||||
namespace BTCPayServer.Client;
|
||||
|
||||
public class GreenfieldValidationException : Exception
|
||||
namespace BTCPayServer.Client
|
||||
{
|
||||
public GreenfieldValidationException(GreenfieldValidationError[] errors) : base(BuildMessage(errors))
|
||||
public class GreenFieldValidationException : Exception
|
||||
{
|
||||
ValidationErrors = errors;
|
||||
}
|
||||
|
||||
private static string BuildMessage(GreenfieldValidationError[] errors)
|
||||
{
|
||||
if (errors == null) throw new ArgumentNullException(nameof(errors));
|
||||
var builder = new StringBuilder();
|
||||
foreach (var error in errors)
|
||||
public GreenFieldValidationException(Models.GreenfieldValidationError[] errors) : base(BuildMessage(errors))
|
||||
{
|
||||
builder.AppendLine($"{error.Path}: {error.Message}");
|
||||
ValidationErrors = errors;
|
||||
}
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
public GreenfieldValidationError[] ValidationErrors { get; }
|
||||
private static string BuildMessage(GreenfieldValidationError[] errors)
|
||||
{
|
||||
if (errors == null)
|
||||
throw new ArgumentNullException(nameof(errors));
|
||||
StringBuilder builder = new StringBuilder();
|
||||
foreach (var error in errors)
|
||||
{
|
||||
builder.AppendLine($"{error.Path}: {error.Message}");
|
||||
}
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
public Models.GreenfieldValidationError[] ValidationErrors { get; }
|
||||
}
|
||||
}
|
||||
|
@ -1,31 +0,0 @@
|
||||
using System;
|
||||
using NBitcoin;
|
||||
using NBitcoin.JsonConverters;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BTCPayServer.Client.JsonConverters
|
||||
{
|
||||
public class MnemonicJsonConverter : JsonConverter<Mnemonic>
|
||||
{
|
||||
public override Mnemonic ReadJson(JsonReader reader, Type objectType, Mnemonic existingValue, bool hasExistingValue,
|
||||
JsonSerializer serializer)
|
||||
{
|
||||
return reader.TokenType switch
|
||||
{
|
||||
JsonToken.String => new Mnemonic((string)reader.Value),
|
||||
JsonToken.Null => null,
|
||||
_ => throw new JsonObjectException(reader.Path, "Mnemonic must be a json string")
|
||||
};
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, Mnemonic value, JsonSerializer serializer)
|
||||
{
|
||||
if (value != null)
|
||||
writer.WriteValue(value.ToString());
|
||||
else
|
||||
{
|
||||
writer.WriteNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -19,7 +19,7 @@ namespace BTCPayServer.Client.JsonConverters
|
||||
|
||||
public override void WriteJson(JsonWriter writer, [AllowNull] NodeInfo value, JsonSerializer serializer)
|
||||
{
|
||||
if (value is not null)
|
||||
if (value is NodeInfo)
|
||||
writer.WriteValue(value.ToString());
|
||||
}
|
||||
}
|
||||
|
@ -22,17 +22,13 @@ namespace BTCPayServer.JsonConverters
|
||||
switch (token.Type)
|
||||
{
|
||||
case JTokenType.Float:
|
||||
if (objectType == typeof(decimal) || objectType == typeof(decimal?))
|
||||
return token.Value<decimal>();
|
||||
if (objectType == typeof(double) || objectType == typeof(double?))
|
||||
return token.Value<double>();
|
||||
throw new JsonSerializationException("Unexpected object type: " + objectType);
|
||||
case JTokenType.Integer:
|
||||
case JTokenType.String:
|
||||
if (objectType == typeof(decimal) || objectType == typeof(decimal?))
|
||||
return decimal.Parse(token.ToString(), NumberStyles.Any, CultureInfo.InvariantCulture);
|
||||
if (objectType == typeof(decimal) || objectType == typeof(decimal?) )
|
||||
return decimal.Parse(token.ToString(), CultureInfo.InvariantCulture);
|
||||
if (objectType == typeof(double) || objectType == typeof(double?))
|
||||
return double.Parse(token.ToString(), NumberStyles.Any, CultureInfo.InvariantCulture);
|
||||
return double.Parse(token.ToString(), CultureInfo.InvariantCulture);
|
||||
|
||||
throw new JsonSerializationException("Unexpected object type: " + objectType);
|
||||
case JTokenType.Null when objectType == typeof(decimal?) || objectType == typeof(double?):
|
||||
return null;
|
||||
|
@ -1,43 +0,0 @@
|
||||
using NBitcoin;
|
||||
using NBitcoin.DataEncoders;
|
||||
using NBitcoin.JsonConverters;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
namespace BTCPayServer.Client.JsonConverters
|
||||
{
|
||||
public class SaneOutpointJsonConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return typeof(OutPoint).GetTypeInfo().IsAssignableFrom(objectType.GetTypeInfo());
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (reader.TokenType == JsonToken.Null)
|
||||
return null;
|
||||
|
||||
if (reader.TokenType != JsonToken.String)
|
||||
throw new JsonObjectException($"Unexpected json token type, expected is {JsonToken.String} and actual is {reader.TokenType}", reader);
|
||||
try
|
||||
{
|
||||
if (!OutPoint.TryParse((string)reader.Value, out var outpoint))
|
||||
throw new JsonObjectException("Invalid bitcoin object of type OutPoint", reader);
|
||||
return outpoint;
|
||||
}
|
||||
catch (EndOfStreamException)
|
||||
{
|
||||
}
|
||||
throw new JsonObjectException("Invalid bitcoin object of type OutPoint", reader);
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
if (value is { })
|
||||
writer.WriteValue(value.ToString());
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user