Compare commits

...

33 Commits
0.5.3 ... main

Author SHA1 Message Date
tastytea c48f1dc3d0
add maintenance mode notice
continuous-integration/drone/push Build is passing Details
2022-11-13 06:24:35 +01:00
tastytea 9a25cd9178
add Windows section to readme
Reported-by: Ben S.
2022-11-13 06:19:51 +01:00
tastytea e74828c19e
don't add -fsanitize=undefined if MinGW is used
Reported-by: Ben S.
2022-11-13 06:17:34 +01:00
tastytea 7255df01e0
add support for testing with catch 3
continuous-integration/drone/push Build is passing Details
2022-08-01 14:21:06 +02:00
tastytea 7de644d841
Add repology badge.
continuous-integration/drone/push Build is passing Details
2021-05-17 23:31:50 +02:00
tastytea 52a849870f
Make direction a string_view in answer_type::parse_pagination(). 2021-02-08 17:28:46 +01:00
tastytea aabcb46602
Update .clang-tidy. 2020-11-30 20:52:56 +01:00
tastytea cca3a4a239
Update Gentoo package installation.
continuous-integration/drone/push Build is passing Details
2020-11-29 05:07:04 +01:00
tastytea 5ec7a119dc
Add hyperlink to AUR.
continuous-integration/drone/push Build is passing Details
2020-11-27 14:46:58 +01:00
tastytea cf4302248f
Typo in CI recipe.
continuous-integration/drone/push Build is passing Details
2020-11-20 22:52:57 +01:00
tastytea cadf0d777e
Version bump 0.5.7.
Forgot to bump the version in the CMake recipe, packages couldn't be
built.
2020-11-13 15:07:41 +01:00
tastytea aeb7396961
Generate API documentation with CMake.
continuous-integration/drone/push Build is passing Details
2020-11-13 14:25:22 +01:00
tastytea f4bd5abd01
Fix some warnings.
Avoid copy, initialize members in header, initialize variables.
2020-11-13 14:17:44 +01:00
tastytea c9211e621e
Reformat examples. 2020-11-13 14:05:28 +01:00
tastytea 3a93aec941
Reformat tests. 2020-11-13 14:01:09 +01:00
tastytea 9efc8d2dfd
Reformat source files. 2020-11-13 14:00:03 +01:00
tastytea 8c7493e68e
Reformat header files. 2020-11-13 13:45:59 +01:00
tastytea 63d2497966
Update .clang-tidy, add .clang-format. 2020-11-13 13:41:13 +01:00
tastytea 4da6929392
Add note about scopes in documentation for ObtainToken::step_1().
continuous-integration/drone/push Build is passing Details
2020-11-13 13:33:24 +01:00
tastytea 24cb2d523d
ObtainToken: Change grant_type to authorization_code.
continuous-integration/drone/push Build is passing Details
client_credentials worked before but not anymore. 🤷
2020-11-13 13:03:49 +01:00
tastytea 41f470d2aa
Add read to scopes in obtain-token example.
Without that, we cannot very our credentials. Mastodon needs
read::accounts, Pleroma needs read.
2020-11-13 13:02:52 +01:00
tastytea e563731efe
Avoid copies, fix warnings. 2020-11-13 12:01:18 +01:00
tastytea ef11508ca1
Bump maximum CMake version to 3.16.
continuous-integration/drone/push Build is passing Details
2020-05-19 19:33:34 +02:00
tastytea c2bc1b5e7b
Only use add_compile_definitions with CMake >= 3.12. 2020-05-19 19:32:34 +02:00
tastytea 3c23f6d1a0
Version bump 0.5.5. 2020-05-19 19:26:51 +02:00
tastytea 3909187f7a
Add -DNDEBUG for non-debug builds.
continuous-integration/drone/push Build is failing Details
2020-05-19 19:24:21 +02:00
tastytea 2ada3b406b
Merge branch 'develop' into main
continuous-integration/drone/push Build is passing Details
2020-04-18 15:44:12 +02:00
tastytea d20818221d
Add Support for Pleroma 2.0.2.
continuous-integration/drone/push Build is passing Details
Add endpoint: /api/pleroma/admin/users/:nickname/update_credentials
2020-04-18 15:25:49 +02:00
tastytea f16e6d61e0
Remove unused using declaration. 2020-04-18 15:25:49 +02:00
tastytea 576c84aa36
Version bump 0.5.4.
continuous-integration/drone/push Build is passing Details
2020-03-21 12:26:42 +01:00
tastytea aea4b0f492
Merge branch 'develop' into main
continuous-integration/drone/push Build was killed Details
2020-03-21 12:25:54 +01:00
tastytea 5bf1e9bf25
Define copy constructor for instance.
continuous-integration/drone/push Build is passing Details
Needed because the underlying CURLWrapper is not copied but freshly created, so
access_token, proxy, cainfo and useragent have to be set.
2020-03-21 11:38:34 +01:00
tastytea 251d8a975c
Set access token in CURLWrapper too if it is set in Instance. 2020-03-21 11:26:23 +01:00
40 changed files with 715 additions and 570 deletions

131
.clang-format Normal file
View File

@ -0,0 +1,131 @@
# -*- mode: yaml -*-
# Written for clang-format 10.
# https://releases.llvm.org/10.0.0/tools/clang/docs/ClangFormatStyleOptions.html
---
DisableFormat: false
Language: Cpp
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
# AlignConsecutiveBitFields: false # clang-format 11
AlignConsecutiveDeclarations: false
AlignConsecutiveMacros: false
AlignEscapedNewlines: DontAlign
AlignOperands: true # clang-format 11: Align
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: false
AllowAllConstructorInitializersOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: Empty
AllowShortCaseLabelsOnASingleLine: false
# AllowShortEnumsOnASingleLine: false # clang-format 11
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: Never
AllowShortLambdasOnASingleLine: Inline
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: true
BinPackParameters: true
BraceWrapping: # If BreakBeforeBraces is set to Custom.
AfterCaseLabel: true
AfterClass: true
AfterControlStatement: Always
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterStruct: true
AfterUnion: true
AfterExternBlock: true
BeforeCatch: true
BeforeElse: true
# BeforeLambdaBody: true # clang-format 11
# BeforeWhile: true # clang-format 11
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeBraces: Custom
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeComma
BreakInheritanceList: BeforeComma
BreakStringLiterals: true
ColumnLimit: 80
# CommentPragmas: 'regex'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: false
FixNamespaceComments: true
ForEachMacros:
- FOREACH
- RANGES_FOR
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Regroup
IncludeCategories: # stdlib headers into own group.
- Regex: '^[^\.]+$'
Priority: 4
# IndentCaseBlocks: false # clang-format 11
IndentCaseLabels: false
# IndentExternBlock: NoIndent # clang-format 11
IndentGotoLabels: false
IndentPPDirectives: AfterHash
IndentWidth: 4
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: true
# MacroBlockBegin: 'string'
# MacroBlockEnd: 'string'
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
# NamespaceMacros: 'string'
PenaltyBreakAssignment: 250
PenaltyBreakBeforeFirstCallParameter: 300
# PenaltyBreakComment: 300
# PenaltyBreakFirstLessLess: 120
# PenaltyBreakString: 1000
# PenaltyBreakTemplateDeclaration: 10
# PenaltyExcessCharacter: 1000000
# PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
# RawStringFormats: # <YAML>
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Auto
# StatementMacros:
# - Q_UNUSED
# - QT_REQUIRE_VERSION
TabWidth: 4
# TypenameMacros:
# - STACK_OF
# - LIST
UseCRLF: false
UseTab: Never
# WhitespaceSensitiveMacros: ['string', 'string'] # clang-format 11
...

View File

@ -1,5 +1,5 @@
# -*- mode: conf; fill-column: 100; -*- # -*- mode: conf; fill-column: 100; -*-
# Written for clang-tidy 9. # Written for clang-tidy 11.
--- ---
Checks: '*, Checks: '*,
@ -25,19 +25,21 @@ Checks: '*,
-hicpp-vararg, -hicpp-vararg,
-fuchsia-statically-constructed-objects, -fuchsia-statically-constructed-objects,
-google-readability-todo, -google-readability-todo,
-modernize-use-trailing-return-type' -modernize-use-trailing-return-type,
CheckOptions: - { key: readability-identifier-naming.ClassCase, value: CamelCase } -fuchsia-multiple-inheritance,
# Clashes with constant private member prefix. (const int _var;) -llvmlibc*'
# - { key: readability-identifier-naming.ConstantCase, value: lower_case } FormatStyle: file # Use .clang-format.
- { key: readability-identifier-naming.EnumCase, value: lower_case } CheckOptions: # ↓ Clashes with static private member prefix. (static int _var;) ↓
- { key: readability-identifier-naming.FunctionCase, value: lower_case } - { key: readability-identifier-naming.VariableCase, value: lower_case }
- { key: readability-identifier-naming.MemberCase, value: lower_case } - { key: readability-identifier-naming.MemberCase, value: lower_case }
- { key: readability-identifier-naming.ParameterCase, value: lower_case }
- { key: readability-identifier-naming.PrivateMemberCase, value: lower_case } - { key: readability-identifier-naming.PrivateMemberCase, value: lower_case }
- { key: readability-identifier-naming.PrivateMemberPrefix, value: _ } - { key: readability-identifier-naming.PrivateMemberPrefix, value: _ }
- { key: readability-identifier-naming.ProtextedMemberCase, value: lower_case } - { key: readability-identifier-naming.ProtectedMemberCase, value: lower_case }
- { key: readability-identifier-naming.ProtectedMemberPrefix, value: _ } - { key: readability-identifier-naming.ProtectedMemberPrefix, value: _ }
- { key: readability-identifier-naming.ClassCase, value: CamelCase }
- { key: readability-identifier-naming.StructCase, value: lower_case } - { key: readability-identifier-naming.StructCase, value: lower_case }
# Clashes with static private member prefix. (static int _var;) - { key: readability-identifier-naming.EnumCase, value: lower_case }
# - { key: readability-identifier-naming.VariableCase, value: lower_case } - { key: readability-identifier-naming.FunctionCase, value: lower_case }
- { key: readability-identifier-naming.ParameterCase, value: lower_case }
... ...

View File

@ -141,7 +141,7 @@ steps:
- apt-get install -qq build-essential cmake lsb-release - apt-get install -qq build-essential cmake lsb-release
- apt-get install -qq libcurl4-openssl-dev - apt-get install -qq libcurl4-openssl-dev
- rm -rf build && mkdir -p build && cd build - rm -rf build && mkdir -p build && cd build
- cmake -G "Unix Makefiles" -SCMAKE_INSTALL_PREFIX=/usr -DWITH_DEB=YES .. - cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=/usr -DWITH_DEB=YES ..
- make - make
- make install DESTDIR=install - make install DESTDIR=install
- make package - make package

1
.gitignore vendored
View File

@ -1,4 +1,3 @@
/build/ /build/
/doc/
/update_doc.sh /update_doc.sh
/examples/example99* /examples/example99*

View File

@ -1,6 +1,6 @@
# Support version 3.9 and above, but use policy settings up to 3.14. # Support version 3.9 and above, but use policy settings up to 3.14.
# 3.9 is needed for project description. # 3.9 is needed for project description.
cmake_minimum_required(VERSION 3.9...3.14) cmake_minimum_required(VERSION 3.9...3.16)
# Ranges are supported from 3.12, set policy to current for < 3.12. # Ranges are supported from 3.12, set policy to current for < 3.12.
if(${CMAKE_VERSION} VERSION_LESS 3.12) if(${CMAKE_VERSION} VERSION_LESS 3.12)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
@ -10,8 +10,17 @@ endif()
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "The type of build.") set(CMAKE_BUILD_TYPE "Release" CACHE STRING "The type of build.")
option(BUILD_SHARED_LIBS "Build shared libraries." YES) option(BUILD_SHARED_LIBS "Build shared libraries." YES)
# Not every non-debug build type adds -DNDEBUG.
if(NOT ${CMAKE_BUILD_TYPE} MATCHES "Debug")
if(${CMAKE_VERSION} VERSION_LESS 3.12)
add_definitions("-DNDEBUG")
else()
add_compile_definitions("NDEBUG")
endif()
endif()
project(mastodonpp project(mastodonpp
VERSION 0.5.3 VERSION 0.5.7
DESCRIPTION "C++ wrapper for the Mastodon and Pleroma APIs." DESCRIPTION "C++ wrapper for the Mastodon and Pleroma APIs."
LANGUAGES CXX) LANGUAGES CXX)
@ -20,6 +29,7 @@ list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
# Project build options. # Project build options.
option(WITH_TESTS "Compile tests." NO) option(WITH_TESTS "Compile tests." NO)
option(WITH_EXAMPLES "Compile examples." NO) option(WITH_EXAMPLES "Compile examples." NO)
option(WITH_DOC "Generate API documentation." NO)
option(WITH_DEB "Prepare for the building of .deb packages." NO) option(WITH_DEB "Prepare for the building of .deb packages." NO)
option(WITH_RPM "Prepare for the building of .rpm packages." NO) option(WITH_RPM "Prepare for the building of .rpm packages." NO)
option(WITH_CLANG-TIDY "Check sourcecode with clang-tidy while compiling." NO) option(WITH_CLANG-TIDY "Check sourcecode with clang-tidy while compiling." NO)
@ -51,4 +61,11 @@ if(WITH_EXAMPLES)
add_subdirectory(examples) add_subdirectory(examples)
endif() endif()
if(WITH_DOC)
include(cmake/Doxygen.cmake)
enable_doxygen(
"${CMAKE_CURRENT_SOURCE_DIR}/include"
"${CMAKE_CURRENT_SOURCE_DIR}/src")
endif()
include(cmake/packages.cmake) include(cmake/packages.cmake)

View File

@ -1,27 +0,0 @@
# -*- mode: conf-unix -*-
INPUT = src/ include/
RECURSIVE = YES
STRIP_FROM_INC_PATH = "include"
EXAMPLE_PATH = examples/
EXAMPLE_RECURSIVE = YES
GENERATE_HTML = YES
HTML_OUTPUT = doc/html
GENERATE_LATEX = NO
ALLOW_UNICODE_NAMES = YES
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ALWAYS_DETAILED_SEC = YES
INLINE_INHERITED_MEMB = NO
INHERIT_DOCS = YES
SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 4
MARKDOWN_SUPPORT = YES
AUTOLINK_SUPPORT = YES
INLINE_SIMPLE_STRUCTS = NO
QUIET = NO
WARNINGS = YES
BUILTIN_STL_SUPPORT = YES
VERBATIM_HEADERS = YES
INLINE_SOURCES = YES
SEARCHENGINE = YES
SHOW_FILES = YES

View File

@ -22,6 +22,10 @@
link:{uri-pleroma}[Pleroma] APIs. It replaces link:{uri-pleroma}[Pleroma] APIs. It replaces
link:{uri-mastodon-cpp}[mastodon-cpp]. link:{uri-mastodon-cpp}[mastodon-cpp].
[IMPORTANT]
mastodonpp is in maintenance mode. I will continue to fix bugs, but won't add
new features. If you'd like to adopt this project, please get in touch.
We aim to create a library that is comfortable, yet minimal. All API endpoints We aim to create a library that is comfortable, yet minimal. All API endpoints
from Mastodon and Pleroma are stored in ``enum class``es, to counteract typos from Mastodon and Pleroma are stored in ``enum class``es, to counteract typos
and make your life easier. The network-facing code is built on and make your life easier. The network-facing code is built on
@ -79,16 +83,24 @@ link:{uri-reference}/examples.html[More examples] are included in the reference.
== Install == Install
[alt="Packaging status" link=https://repology.org/project/mastodonpp/versions]
image::https://repology.org/badge/vertical-allrepos/mastodonpp.svg[]
=== Gentoo === Gentoo
[source,shell] [source,shell]
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
eselect repository enable tastytea eselect repository enable guru
echo 'dev-cpp/mastodonpp' >> /etc/portage/package.accept_keywords/mastodonpp echo 'dev-cpp/mastodonpp' >> /etc/portage/package.accept_keywords/mastodonpp
emaint sync -r tastytea emaint sync -r guru
emerge -a dev-cpp/mastodonpp emerge -a dev-cpp/mastodonpp
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
=== Arch
The git-version is available via the AUR:
<https://aur.archlinux.org/packages/mastodonpp-git/>.
=== Debian and Ubuntu === Debian and Ubuntu
We automatically generate packages for Debian buster (10) and Ubuntu bionic We automatically generate packages for Debian buster (10) and Ubuntu bionic
@ -151,6 +163,7 @@ cmake --build . -- -j$(nproc --ignore=1)
* `-DCMAKE_BUILD_TYPE=Debug` for a debug build. * `-DCMAKE_BUILD_TYPE=Debug` for a debug build.
* `-DWITH_TESTS=YES` if you want to compile the tests. * `-DWITH_TESTS=YES` if you want to compile the tests.
* `-DWITH_EXAMPLES=YES` if you want to compile the examples. * `-DWITH_EXAMPLES=YES` if you want to compile the examples.
* `-DWITH_DOC=YES` if you want to generate the API documentation.
* `-DWITH_CLANG-TIDY=YES` to check the sourcecode with * `-DWITH_CLANG-TIDY=YES` to check the sourcecode with
link:{uri-clang-tidy}[clang-tidy] while compiling. link:{uri-clang-tidy}[clang-tidy] while compiling.
* One of: * One of:
@ -159,4 +172,10 @@ cmake --build . -- -j$(nproc --ignore=1)
To create a deb or rpm package, run `make package` after compiling. To create a deb or rpm package, run `make package` after compiling.
===== Windows
mastodonpp has been reported to compile with MinGW GCC, but
`http_method::DELETE` has to be renamed, because Windows headers define a
`DELETE` macro.
include::{uri-base}/raw/branch/main/CONTRIBUTING.adoc[] include::{uri-base}/raw/branch/main/CONTRIBUTING.adoc[]

View File

@ -1,11 +0,0 @@
#!/bin/sh
project="$(realpath --relative-base=.. .)"
version="$(grep -Eo '[0-9]+.[0-9]+.[0-9]+$' CMakeLists.txt)"
if [[ -f Doxyfile ]]; then
mkdir -p doc
(doxygen -s -g - && cat Doxyfile &&
echo "PROJECT_NAME = ${project}" &&
echo "PROJECT_NUMBER = ${version}") | doxygen -
fi

43
cmake/Doxygen.cmake Normal file
View File

@ -0,0 +1,43 @@
include(GNUInstallDirs)
function(enable_doxygen)
find_package(Doxygen REQUIRED dot)
set(DOXYGEN_RECURSIVE YES)
set(DOXYGEN_STRIP_FROM_INC_PATH "include")
if (WITH_EXAMPLES)
set(DOXYGEN_EXAMPLE_PATH "examples/")
set(DOXYGEN_EXAMPLE_RECURSIVE YES)
endif()
set(DOXYGEN_GENERATE_HTML YES)
set(DOXYGEN_HTML_OUTPUT "doc/html")
set(DOXYGEN_GENERATE_LATEX NO)
set(DOXYGEN_ALLOW_UNICODE_NAMES YES)
set(DOXYGEN_BRIEF_MEMBER_DESC YES)
set(DOXYGEN_REPEAT_BRIEF YES)
set(DOXYGEN_ALWAYS_DETAILED_SEC YES)
set(DOXYGEN_INLINE_INHERITED_MEMB NO)
set(DOXYGEN_INHERIT_DOCS YES)
set(DOXYGEN_SEPARATE_MEMBER_PAGES NO)
set(DOXYGEN_TAB_SIZE 4)
set(DOXYGEN_MARKDOWN_SUPPORT YES)
set(DOXYGEN_AUTOLINK_SUPPORT YES)
set(DOXYGEN_INLINE_SIMPLE_STRUCTS NO)
set(DOXYGEN_QUIET YES)
set(DOXYGEN_WARNINGS YES)
set(DOXYGEN_WARN_IF_UNDOCUMENTED YES)
set(DOXYGEN_BUILTIN_STL_SUPPORT YES)
set(DOXYGEN_VERBATIM_HEADERS YES)
set(DOXYGEN_INLINE_SOURCES YES)
set(DOXYGEN_SEARCHENGINE YES)
set(DOXYGEN_SHOW_FILES YES)
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/doc")
doxygen_add_docs(${PROJECT_NAME}_doxygen "${ARGV}")
# Make sure doxygen is run with every build.
add_custom_target(${PROJECT_NAME}_docs ALL DEPENDS ${PROJECT_NAME}_doxygen)
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc/html
DESTINATION "${CMAKE_INSTALL_DOCDIR}")
endfunction()

View File

@ -22,7 +22,6 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang"
"-Wdouble-promotion" "-Wdouble-promotion"
"-Wformat=2" "-Wformat=2"
"-ftrapv" "-ftrapv"
"-fsanitize=undefined"
"-Og" "-Og"
"-fno-omit-frame-pointer") "-fno-omit-frame-pointer")
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
@ -40,15 +39,21 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang"
endif() endif()
endif() endif()
endif() endif()
if(NOT MINGW)
list(APPEND DEBUG_CXXFLAGS
"-fsanitize=undefined")
endif()
add_compile_options("$<$<CONFIG:Debug>:${DEBUG_CXXFLAGS}>") add_compile_options("$<$<CONFIG:Debug>:${DEBUG_CXXFLAGS}>")
set(DEBUG_LDFLAGS if(NOT MINGW)
"-fsanitize=undefined") set(DEBUG_LDFLAGS
# add_link_options was introduced in version 3.13. "-fsanitize=undefined")
if(${CMAKE_VERSION} VERSION_LESS 3.13) # add_link_options was introduced in version 3.13.
set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${DEBUG_LDFLAGS}") if(${CMAKE_VERSION} VERSION_LESS 3.13)
else() set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${DEBUG_LDFLAGS}")
add_link_options("$<$<CONFIG:Debug>:${DEBUG_LDFLAGS}>") else()
add_link_options("$<$<CONFIG:Debug>:${DEBUG_LDFLAGS}>")
endif()
endif() endif()
else() else()
message(STATUS message(STATUS

View File

@ -16,7 +16,7 @@
// Print information about an instance (/api/v1/instance). // Print information about an instance (/api/v1/instance).
#if __has_include("mastodonpp.hpp") #if __has_include("mastodonpp.hpp")
# include "mastodonpp.hpp" // We're building mastodonpp. # include "mastodonpp.hpp" // We're building mastodonpp.
#else #else
# include <mastodonpp/mastodonpp.hpp> // We're building outside mastodonpp. # include <mastodonpp/mastodonpp.hpp> // We're building outside mastodonpp.
#endif #endif
@ -27,11 +27,11 @@
#include <vector> #include <vector>
namespace masto = mastodonpp; namespace masto = mastodonpp;
using std::cout;
using std::cerr; using std::cerr;
using std::cout;
using std::endl; using std::endl;
using std::to_string;
using std::string_view; using std::string_view;
using std::to_string;
using std::vector; using std::vector;
int main(int argc, char *argv[]) int main(int argc, char *argv[])

View File

@ -16,7 +16,7 @@
// Print new public events (/api/v1/streaming/public). // Print new public events (/api/v1/streaming/public).
#if __has_include("mastodonpp.hpp") #if __has_include("mastodonpp.hpp")
# include "mastodonpp.hpp" // We're building mastodonpp. # include "mastodonpp.hpp" // We're building mastodonpp.
#else #else
# include <mastodonpp/mastodonpp.hpp> // We're building outside mastodonpp. # include <mastodonpp/mastodonpp.hpp> // We're building outside mastodonpp.
#endif #endif
@ -30,14 +30,14 @@
namespace masto = mastodonpp; namespace masto = mastodonpp;
using namespace std::chrono_literals; using namespace std::chrono_literals;
using std::cout;
using std::cerr; using std::cerr;
using std::cout;
using std::endl; using std::endl;
using std::to_string;
using std::string_view; using std::string_view;
using std::thread; using std::thread;
using std::this_thread::sleep_for; using std::to_string;
using std::vector; using std::vector;
using std::this_thread::sleep_for;
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
@ -61,8 +61,10 @@ int main(int argc, char *argv[])
if (answer && answer.body == "OK") if (answer && answer.body == "OK")
{ {
// Make a thread, get all public events. // Make a thread, get all public events.
// clang-format off
thread stream_thread{[&] thread stream_thread{[&]
{ {
// clang-format on
answer = connection.get(masto::API::v1::streaming_public); answer = connection.get(masto::API::v1::streaming_public);
}}; }};
@ -73,8 +75,8 @@ int main(int argc, char *argv[])
for (const auto &event : connection.get_new_events()) for (const auto &event : connection.get_new_events())
{ {
// Print type of event and the beginning of the data. // Print type of event and the beginning of the data.
cout << event.type << ": " cout << event.type << ": " << event.data.substr(0, 70)
<< event.data.substr(0, 70) << "" << endl; << "" << endl;
} }
} }

View File

@ -16,7 +16,7 @@
// Post a status (/api/v1/status). // Post a status (/api/v1/status).
#if __has_include("mastodonpp.hpp") #if __has_include("mastodonpp.hpp")
# include "mastodonpp.hpp" // We're building mastodonpp. # include "mastodonpp.hpp" // We're building mastodonpp.
#else #else
# include <mastodonpp/mastodonpp.hpp> // We're building outside mastodonpp. # include <mastodonpp/mastodonpp.hpp> // We're building outside mastodonpp.
#endif #endif
@ -27,11 +27,11 @@
#include <vector> #include <vector>
namespace masto = mastodonpp; namespace masto = mastodonpp;
using std::cout;
using std::cerr; using std::cerr;
using std::cout;
using std::endl; using std::endl;
using std::to_string;
using std::string_view; using std::string_view;
using std::to_string;
using std::vector; using std::vector;
int main(int argc, char *argv[]) int main(int argc, char *argv[])
@ -51,12 +51,12 @@ int main(int argc, char *argv[])
// Set up the parameters. // Set up the parameters.
constexpr auto poll_seconds{60 * 60 * 24 * 2}; // 2 days. constexpr auto poll_seconds{60 * 60 * 24 * 2}; // 2 days.
const masto::parametermap parameters const masto::parametermap parameters{{"status", "How is the weather?"},
{ {"poll[options]",
{"status", "How is the weather?"}, vector<string_view>{"Nice",
{"poll[options]", vector<string_view>{"Nice", "not nice"}}, "not nice"}},
{"poll[expires_in]", to_string(poll_seconds)} {"poll[expires_in]",
}; to_string(poll_seconds)}};
// Post the status. // Post the status.
auto answer{connection.post(masto::API::v1::statuses, parameters)}; auto answer{connection.post(masto::API::v1::statuses, parameters)};

View File

@ -16,7 +16,7 @@
// Post a status (/api/v1/status) with an attachment (/api/v1/media). // Post a status (/api/v1/status) with an attachment (/api/v1/media).
#if __has_include("mastodonpp.hpp") #if __has_include("mastodonpp.hpp")
# include "mastodonpp.hpp" // We're building mastodonpp. # include "mastodonpp.hpp" // We're building mastodonpp.
#else #else
# include <mastodonpp/mastodonpp.hpp> // We're building outside mastodonpp. # include <mastodonpp/mastodonpp.hpp> // We're building outside mastodonpp.
#endif #endif
@ -27,12 +27,12 @@
#include <vector> #include <vector>
namespace masto = mastodonpp; namespace masto = mastodonpp;
using std::cout;
using std::cerr; using std::cerr;
using std::cout;
using std::endl; using std::endl;
using std::string; using std::string;
using std::to_string;
using std::string_view; using std::string_view;
using std::to_string;
using std::vector; using std::vector;
int main(int argc, char *argv[]) int main(int argc, char *argv[])
@ -54,10 +54,8 @@ int main(int argc, char *argv[])
// Create attachment. // Create attachment.
auto answer{connection.post(masto::API::v1::media, auto answer{connection.post(masto::API::v1::media,
{ {{"file", string("@file:") += filename},
{"file", string("@file:") += filename}, {"description", "Test."}})};
{"description", "Test."}
})};
// Get the ID of the attachment. // Get the ID of the attachment.
// You normally would use a JSON parser, of course. I don't use one // You normally would use a JSON parser, of course. I don't use one
@ -69,11 +67,9 @@ int main(int argc, char *argv[])
// Post the status. Note that “media_ids” always has to be a vector. // Post the status. Note that “media_ids” always has to be a vector.
answer = connection.post(masto::API::v1::statuses, answer = connection.post(masto::API::v1::statuses,
{ {{"status", "Attachment test."},
{"status", "Attachment test."}, {"media_ids",
{"media_ids", vector<string_view>{media_id}}});
vector<string_view>{media_id}}
});
if (answer) if (answer)
{ {
cout << "Successfully posted " << filename << ".\n"; cout << "Successfully posted " << filename << ".\n";

View File

@ -16,7 +16,7 @@
// Update notification settings (/api/pleroma/notification_settings). // Update notification settings (/api/pleroma/notification_settings).
#if __has_include("mastodonpp.hpp") #if __has_include("mastodonpp.hpp")
# include "mastodonpp.hpp" // We're building mastodonpp. # include "mastodonpp.hpp" // We're building mastodonpp.
#else #else
# include <mastodonpp/mastodonpp.hpp> // We're building outside mastodonpp. # include <mastodonpp/mastodonpp.hpp> // We're building outside mastodonpp.
#endif #endif
@ -27,11 +27,11 @@
#include <vector> #include <vector>
namespace masto = mastodonpp; namespace masto = mastodonpp;
using std::cout;
using std::cerr; using std::cerr;
using std::cout;
using std::endl; using std::endl;
using std::to_string;
using std::string_view; using std::string_view;
using std::to_string;
using std::vector; using std::vector;
int main(int argc, char *argv[]) int main(int argc, char *argv[])
@ -50,14 +50,14 @@ int main(int argc, char *argv[])
masto::Connection connection{instance}; masto::Connection connection{instance};
// Update the settings. // Update the settings.
const auto answer{connection.put( const auto answer{
masto::API::pleroma::notification_settings, connection.put(masto::API::pleroma::notification_settings,
{ {
{"followers", "true"}, {"followers", "true"},
{"follows", "true"}, {"follows", "true"},
{"remote", "true"}, {"remote", "true"},
{"local", "true"}, {"local", "true"},
})}; })};
if (answer) if (answer)
{ {
cout << answer << endl; cout << answer << endl;

View File

@ -16,7 +16,7 @@
// Update account display name settings (/api/v1/accounts/update_credentials). // Update account display name settings (/api/v1/accounts/update_credentials).
#if __has_include("mastodonpp.hpp") #if __has_include("mastodonpp.hpp")
# include "mastodonpp.hpp" // We're building mastodonpp. # include "mastodonpp.hpp" // We're building mastodonpp.
#else #else
# include <mastodonpp/mastodonpp.hpp> // We're building outside mastodonpp. # include <mastodonpp/mastodonpp.hpp> // We're building outside mastodonpp.
#endif #endif
@ -27,11 +27,11 @@
#include <vector> #include <vector>
namespace masto = mastodonpp; namespace masto = mastodonpp;
using std::cout;
using std::cerr; using std::cerr;
using std::cout;
using std::endl; using std::endl;
using std::to_string;
using std::string_view; using std::string_view;
using std::to_string;
using std::vector; using std::vector;
int main(int argc, char *argv[]) int main(int argc, char *argv[])
@ -52,11 +52,9 @@ int main(int argc, char *argv[])
masto::Connection connection{instance}; masto::Connection connection{instance};
// Update the settings. // Update the settings.
const auto answer{connection.patch( const auto answer{
masto::API::v1::accounts_update_credentials, connection.patch(masto::API::v1::accounts_update_credentials,
{ {{"display_name", name}})};
{"display_name", name}
})};
if (answer) if (answer)
{ {
cout << "Successfully changed display name.\n"; cout << "Successfully changed display name.\n";

View File

@ -16,7 +16,7 @@
// Post a status (/api/v1/status), then delete it (/api/v1/statuses/:id). // Post a status (/api/v1/status), then delete it (/api/v1/statuses/:id).
#if __has_include("mastodonpp.hpp") #if __has_include("mastodonpp.hpp")
# include "mastodonpp.hpp" // We're building mastodonpp. # include "mastodonpp.hpp" // We're building mastodonpp.
#else #else
# include <mastodonpp/mastodonpp.hpp> // We're building outside mastodonpp. # include <mastodonpp/mastodonpp.hpp> // We're building outside mastodonpp.
#endif #endif
@ -30,13 +30,13 @@
namespace masto = mastodonpp; namespace masto = mastodonpp;
using namespace std::chrono_literals; using namespace std::chrono_literals;
using std::cout;
using std::cerr; using std::cerr;
using std::cout;
using std::endl; using std::endl;
using std::to_string;
using std::string_view; using std::string_view;
using std::this_thread::sleep_for; using std::to_string;
using std::vector; using std::vector;
using std::this_thread::sleep_for;
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {

View File

@ -16,7 +16,7 @@
// Obtain an access token and verify that it works. // Obtain an access token and verify that it works.
#if __has_include("mastodonpp.hpp") #if __has_include("mastodonpp.hpp")
# include "mastodonpp.hpp" // We're building mastodonpp. # include "mastodonpp.hpp" // We're building mastodonpp.
#else #else
# include <mastodonpp/mastodonpp.hpp> // We're building outside mastodonpp. # include <mastodonpp/mastodonpp.hpp> // We're building outside mastodonpp.
#endif #endif
@ -28,14 +28,14 @@
#include <vector> #include <vector>
namespace masto = mastodonpp; namespace masto = mastodonpp;
using std::exit;
using std::cout;
using std::cerr; using std::cerr;
using std::endl;
using std::cin; using std::cin;
using std::cout;
using std::endl;
using std::exit;
using std::string; using std::string;
using std::to_string;
using std::string_view; using std::string_view;
using std::to_string;
using std::vector; using std::vector;
void handle_error(const masto::answer_type &answer); void handle_error(const masto::answer_type &answer);
@ -57,7 +57,9 @@ int main(int argc, char *argv[])
// Create an “Application” (/api/v1/apps), // Create an “Application” (/api/v1/apps),
// and get URI for the authorization code (/oauth/authorize). // and get URI for the authorization code (/oauth/authorize).
auto answer{token.step_1("Testclient", "read:blocks read:mutes", // NOTE: Mastodon only needs read:accounts for verify_credentials but
// Pleroma needs the full read scope.
auto answer{token.step_1("Testclient", "read write:favourites",
"https://example.com/")}; "https://example.com/")};
if (!answer) if (!answer)
{ {
@ -107,8 +109,8 @@ void handle_error(const masto::answer_type &answer)
else else
{ {
// Network errors like “Couldn't resolve host.”. // Network errors like “Couldn't resolve host.”.
cerr << "libcurl error " << to_string(answer.curl_error_code) cerr << "libcurl error " << to_string(answer.curl_error_code) << ": "
<< ": " << answer.error_message << endl; << answer.error_message << endl;
} }
exit(1); exit(1);

View File

@ -17,7 +17,7 @@
// nlohmann-json. <https://github.com/nlohmann/json> // nlohmann-json. <https://github.com/nlohmann/json>
#if __has_include("mastodonpp.hpp") #if __has_include("mastodonpp.hpp")
# include "mastodonpp.hpp" // We're building mastodonpp. # include "mastodonpp.hpp" // We're building mastodonpp.
#else #else
# include <mastodonpp/mastodonpp.hpp> // We're building outside mastodonpp. # include <mastodonpp/mastodonpp.hpp> // We're building outside mastodonpp.
#endif #endif
@ -26,19 +26,19 @@
#if __has_include(<nlohmann/json.hpp>) #if __has_include(<nlohmann/json.hpp>)
# include <nlohmann/json.hpp> # include <nlohmann/json.hpp>
#include <cstdlib> # include <cstdlib>
#include <iostream> # include <iostream>
#include <string> # include <string>
#include <string_view> # include <string_view>
#include <vector> # include <vector>
namespace masto = mastodonpp; namespace masto = mastodonpp;
using json = nlohmann::json; using json = nlohmann::json;
using std::exit;
using std::cout;
using std::cerr; using std::cerr;
using std::to_string; using std::cout;
using std::exit;
using std::string_view; using std::string_view;
using std::to_string;
using std::vector; using std::vector;
void handle_error(const masto::answer_type &answer); void handle_error(const masto::answer_type &answer);
@ -60,10 +60,7 @@ int main(int argc, char *argv[])
// Get the last 4 public statuses of the instance. // Get the last 4 public statuses of the instance.
auto answer{connection.get(masto::API::v1::timelines_public, auto answer{connection.get(masto::API::v1::timelines_public,
{ {{"limit", "4"}, {"local", "true"}})};
{"limit", "4"},
{"local", "true"}
})};
if (answer) if (answer)
{ {
// Parse JSON string. // Parse JSON string.
@ -129,8 +126,8 @@ void handle_error(const masto::answer_type &answer)
else else
{ {
// Network errors like “Couldn't resolve host.”. // Network errors like “Couldn't resolve host.”.
cerr << "libcurl error " << to_string(answer.curl_error_code) cerr << "libcurl error " << to_string(answer.curl_error_code) << ": "
<< ": " << answer.error_message << '\n'; << answer.error_message << '\n';
} }
exit(1); exit(1);
@ -138,11 +135,11 @@ void handle_error(const masto::answer_type &answer)
#else #else
#include <iostream> # include <iostream>
int main() int main()
{ {
std::cout << "Example could not be compiled " std::cout << "Example could not be compiled "
"because nlohmann-json was not found.\n"; "because nlohmann-json was not found.\n";
} }
#endif // __has_include(<nlohmann/json.hpp>) #endif // __has_include(<nlohmann/json.hpp>)

View File

@ -31,7 +31,7 @@ using std::variant;
/*! /*!
* @brief Holds %API endpoints. * @brief Holds %API endpoints.
* *
* Supported %API endpoints: Mastodon 3.0.1, Pleroma 2.0.0. * Supported %API endpoints: Mastodon 3.0.1, Pleroma 2.0.2.
* *
* @since 0.1.0 * @since 0.1.0
* *
@ -271,6 +271,7 @@ public:
admin_users_revoke_invite, admin_users_revoke_invite,
admin_users_email_invite, admin_users_email_invite,
admin_users_nickname_password_reset, admin_users_nickname_password_reset,
admin_users_nickname_update_credentials,
admin_users_force_password_reset, admin_users_force_password_reset,
admin_reports, admin_reports,
admin_grouped_reports, admin_grouped_reports,
@ -321,7 +322,7 @@ public:
* *
* @since 0.1.0 * @since 0.1.0
*/ */
using endpoint_type = variant<v1,v2,oauth,other,pleroma>; using endpoint_type = variant<v1, v2, oauth, other, pleroma>;
/*! /*!
* @brief Constructs an API object. You should never need this. * @brief Constructs an API object. You should never need this.
@ -338,17 +339,16 @@ public:
* *
* @since 0.1.0 * @since 0.1.0
*/ */
[[nodiscard]] [[nodiscard]] inline string_view to_string_view() const
inline string_view to_string_view() const
{ {
return _endpoint_map.at(_endpoint); return _endpoint_map.at(_endpoint);
} }
private: private:
const endpoint_type _endpoint; const endpoint_type _endpoint;
static const map<endpoint_type,string_view> _endpoint_map; static const map<endpoint_type, string_view> _endpoint_map;
}; };
} // namespace mastodonpp } // namespace mastodonpp
#endif // MASTODONPP_API_HPP #endif // MASTODONPP_API_HPP

View File

@ -40,7 +40,7 @@ using std::vector;
* *
* @since 0.1.0 * @since 0.1.0
*/ */
using endpoint_variant = variant<API::endpoint_type,string_view>; using endpoint_variant = variant<API::endpoint_type, string_view>;
/*! /*!
* @brief A stream event. * @brief A stream event.
@ -106,10 +106,10 @@ public:
~Connection() noexcept override = default; ~Connection() noexcept override = default;
//! Copy assignment operator //! Copy assignment operator
Connection& operator=(const Connection &other) = delete; Connection &operator=(const Connection &other) = delete;
//! Move assignment operator //! Move assignment operator
Connection& operator=(Connection &&other) noexcept = delete; Connection &operator=(Connection &&other) noexcept = delete;
/*! /*!
* @brief Make a HTTP GET call with parameters. * @brief Make a HTTP GET call with parameters.
@ -129,9 +129,8 @@ public:
* *
* @since 0.1.0 * @since 0.1.0
*/ */
[[nodiscard]] [[nodiscard]] answer_type get(const endpoint_variant &endpoint,
answer_type get(const endpoint_variant &endpoint, const parametermap &parameters);
const parametermap &parameters);
/*! /*!
* @brief Make a HTTP GET call. * @brief Make a HTTP GET call.
@ -145,8 +144,7 @@ public:
* *
* @since 0.1.0 * @since 0.1.0
*/ */
[[nodiscard]] [[nodiscard]] inline answer_type get(const endpoint_variant &endpoint)
inline answer_type get(const endpoint_variant &endpoint)
{ {
return get(endpoint, {}); return get(endpoint, {});
} }
@ -171,9 +169,8 @@ public:
* *
* @since 0.1.0 * @since 0.1.0
*/ */
[[nodiscard]] [[nodiscard]] answer_type post(const endpoint_variant &endpoint,
answer_type post(const endpoint_variant &endpoint, const parametermap &parameters);
const parametermap &parameters);
/*! /*!
* @brief Make a HTTP POST call. * @brief Make a HTTP POST call.
@ -182,8 +179,7 @@ public:
* *
* @since 0.1.0 * @since 0.1.0
*/ */
[[nodiscard]] [[nodiscard]] inline answer_type post(const endpoint_variant &endpoint)
inline answer_type post(const endpoint_variant &endpoint)
{ {
return post(endpoint, {}); return post(endpoint, {});
} }
@ -197,9 +193,8 @@ public:
* *
* @since 0.2.0 * @since 0.2.0
*/ */
[[nodiscard]] [[nodiscard]] answer_type patch(const endpoint_variant &endpoint,
answer_type patch(const endpoint_variant &endpoint, const parametermap &parameters);
const parametermap &parameters);
/*! /*!
* @brief Make a HTTP PATCH call. * @brief Make a HTTP PATCH call.
@ -208,8 +203,7 @@ public:
* *
* @since 0.2.0 * @since 0.2.0
*/ */
[[nodiscard]] [[nodiscard]] inline answer_type patch(const endpoint_variant &endpoint)
inline answer_type patch(const endpoint_variant &endpoint)
{ {
return patch(endpoint, {}); return patch(endpoint, {});
} }
@ -223,9 +217,8 @@ public:
* *
* @since 0.2.0 * @since 0.2.0
*/ */
[[nodiscard]] [[nodiscard]] answer_type put(const endpoint_variant &endpoint,
answer_type put(const endpoint_variant &endpoint, const parametermap &parameters);
const parametermap &parameters);
/*! /*!
* @brief Make a HTTP PUT call. * @brief Make a HTTP PUT call.
@ -234,8 +227,7 @@ public:
* *
* @since 0.2.0 * @since 0.2.0
*/ */
[[nodiscard]] [[nodiscard]] inline answer_type put(const endpoint_variant &endpoint)
inline answer_type put(const endpoint_variant &endpoint)
{ {
return put(endpoint, {}); return put(endpoint, {});
} }
@ -249,9 +241,8 @@ public:
* *
* @since 0.2.0 * @since 0.2.0
*/ */
[[nodiscard]] [[nodiscard]] answer_type del(const endpoint_variant &endpoint,
answer_type del(const endpoint_variant &endpoint, const parametermap &parameters);
const parametermap &parameters);
/*! /*!
* @brief Make a HTTP DELETE call. * @brief Make a HTTP DELETE call.
@ -260,8 +251,7 @@ public:
* *
* @since 0.2.0 * @since 0.2.0
*/ */
[[nodiscard]] [[nodiscard]] inline answer_type del(const endpoint_variant &endpoint)
inline answer_type del(const endpoint_variant &endpoint)
{ {
return del(endpoint, {}); return del(endpoint, {});
} }
@ -291,14 +281,15 @@ public:
{ {
CURLWrapper::cancel_stream(); CURLWrapper::cancel_stream();
} }
private: private:
const Instance &_instance; const Instance &_instance;
const string_view _baseuri; const string_view _baseuri;
[[nodiscard]] [[nodiscard]] string
string endpoint_to_uri(const endpoint_variant &endpoint) const; endpoint_to_uri(const endpoint_variant &endpoint) const;
}; };
} // namespace mastodonpp } // namespace mastodonpp
#endif // MASTODONPP_CONNECTION_HPP #endif // MASTODONPP_CONNECTION_HPP

View File

@ -17,9 +17,8 @@
#ifndef MASTODONPP_CURL_WRAPPER_HPP #ifndef MASTODONPP_CURL_WRAPPER_HPP
#define MASTODONPP_CURL_WRAPPER_HPP #define MASTODONPP_CURL_WRAPPER_HPP
#include "types.hpp"
#include "curl/curl.h" #include "curl/curl.h"
#include "types.hpp"
#include <mutex> #include <mutex>
#include <string> #include <string>
@ -39,11 +38,11 @@ using std::string_view;
*/ */
enum class http_method enum class http_method
{ {
GET, // NOLINT(readability-identifier-naming) GET, // NOLINT(readability-identifier-naming)
POST, // NOLINT(readability-identifier-naming) POST, // NOLINT(readability-identifier-naming)
PATCH, // NOLINT(readability-identifier-naming) PATCH, // NOLINT(readability-identifier-naming)
PUT, // NOLINT(readability-identifier-naming) PUT, // NOLINT(readability-identifier-naming)
DELETE // NOLINT(readability-identifier-naming) DELETE // NOLINT(readability-identifier-naming)
}; };
/*! /*!
@ -92,10 +91,10 @@ public:
virtual ~CURLWrapper() noexcept; virtual ~CURLWrapper() noexcept;
//! Copy assignment operator //! Copy assignment operator
CURLWrapper& operator=(const CURLWrapper &other) = delete; CURLWrapper &operator=(const CURLWrapper &other) = delete;
//! Move assignment operator //! Move assignment operator
CURLWrapper& operator=(CURLWrapper &&other) noexcept = delete; CURLWrapper &operator=(CURLWrapper &&other) noexcept = delete;
/*! /*!
* @brief Returns pointer to the CURL easy handle. * @brief Returns pointer to the CURL easy handle.
@ -123,12 +122,11 @@ public:
* *
* @since 0.3.0 * @since 0.3.0
*/ */
[[nodiscard]] [[nodiscard]] inline string escape_url(const string_view url) const
inline string escape_url(const string_view url) const
{ {
char *cbuf{curl_easy_escape(_connection, url.data(), char *cbuf{curl_easy_escape(_connection, url.data(),
static_cast<int>(url.size()))}; static_cast<int>(url.size()))};
const string sbuf{cbuf}; string sbuf{cbuf};
curl_free(cbuf); curl_free(cbuf);
return sbuf; return sbuf;
} }
@ -145,12 +143,11 @@ public:
* *
* @since 0.3.0 * @since 0.3.0
*/ */
[[nodiscard]] [[nodiscard]] inline string unescape_url(const string_view url) const
inline string unescape_url(const string_view url) const
{ {
char *cbuf{curl_easy_unescape(_connection, url.data(), char *cbuf{curl_easy_unescape(_connection, url.data(),
static_cast<int>(url.size()), nullptr)}; static_cast<int>(url.size()), nullptr)};
const string sbuf{cbuf}; string sbuf{cbuf};
curl_free(cbuf); curl_free(cbuf);
return sbuf; return sbuf;
} }
@ -164,8 +161,7 @@ public:
*/ */
void setup_connection_properties(string_view proxy, void setup_connection_properties(string_view proxy,
string_view access_token, string_view access_token,
string_view cainfo, string_view cainfo, string_view useragent);
string_view useragent);
protected: protected:
/*! /*!
@ -187,17 +183,16 @@ protected:
* *
* @since 0.1.0 * @since 0.1.0
*/ */
[[nodiscard]] [[nodiscard]] answer_type make_request(const http_method &method,
answer_type make_request(const http_method &method, string uri, string uri,
const parametermap &parameters); const parametermap &parameters);
/*! /*!
* @brief Returns a reference to the buffer libcurl writes into. * @brief Returns a reference to the buffer libcurl writes into.
* *
* @since 0.1.0 * @since 0.1.0
*/ */
[[nodiscard]] [[nodiscard]] inline string &get_buffer()
inline string &get_buffer()
{ {
return _curl_buffer_body; return _curl_buffer_body;
} }
@ -235,7 +230,6 @@ protected:
*/ */
void set_access_token(string_view access_token); void set_access_token(string_view access_token);
/*! /*!
* @brief Set path to Certificate Authority (CA) bundle. * @brief Set path to Certificate Authority (CA) bundle.
* *
@ -251,11 +245,11 @@ protected:
virtual void set_useragent(string_view useragent); virtual void set_useragent(string_view useragent);
private: private:
CURL *_connection; CURL *_connection{nullptr};
char _curl_buffer_error[CURL_ERROR_SIZE]; char _curl_buffer_error[CURL_ERROR_SIZE]{'\0'};
string _curl_buffer_headers; string _curl_buffer_headers;
string _curl_buffer_body; string _curl_buffer_body;
bool _stream_cancelled; bool _stream_cancelled{false};
/*! /*!
* @brief Initializes curl and sets up connection. * @brief Initializes curl and sets up connection.
@ -282,7 +276,7 @@ private:
static inline size_t writer_body_wrapper(char *data, size_t sz, static inline size_t writer_body_wrapper(char *data, size_t sz,
size_t nmemb, void *f) size_t nmemb, void *f)
{ {
return static_cast<CURLWrapper*>(f)->writer_body(data, sz, nmemb); return static_cast<CURLWrapper *>(f)->writer_body(data, sz, nmemb);
} }
//! @copydoc writer_body //! @copydoc writer_body
@ -292,7 +286,7 @@ private:
static inline size_t writer_header_wrapper(char *data, size_t sz, static inline size_t writer_header_wrapper(char *data, size_t sz,
size_t nmemb, void *f) size_t nmemb, void *f)
{ {
return static_cast<CURLWrapper*>(f)->writer_header(data, sz, nmemb); return static_cast<CURLWrapper *>(f)->writer_header(data, sz, nmemb);
} }
/*! /*!
@ -303,15 +297,15 @@ private:
* @since 0.1.0 * @since 0.1.0
*/ */
int progress(void *clientp, curl_off_t dltotal, curl_off_t dlnow, int progress(void *clientp, curl_off_t dltotal, curl_off_t dlnow,
curl_off_t ultotal, curl_off_t ulnow); curl_off_t ultotal, curl_off_t ulnow) const;
//! @copydoc writer_body_wrapper //! @copydoc writer_body_wrapper
static inline int progress_wrapper(void *f, void *clientp, static inline int progress_wrapper(void *f, void *clientp,
curl_off_t dltotal, curl_off_t dlnow, curl_off_t dltotal, curl_off_t dlnow,
curl_off_t ultotal, curl_off_t ulnow) curl_off_t ultotal, curl_off_t ulnow)
{ {
return static_cast<CURLWrapper*>(f)->progress(clientp, dltotal, dlnow, return static_cast<CURLWrapper *>(f)->progress(clientp, dltotal, dlnow,
ultotal, ulnow); ultotal, ulnow);
} }
/*! /*!
@ -354,8 +348,8 @@ private:
* *
* @since 0.2.0 * @since 0.2.0
*/ */
static void add_mime_part(curl_mime *mime, static void add_mime_part(curl_mime *mime, string_view name,
string_view name, string_view data); string_view data);
/*! /*!
* @brief Convert parametermap to `*curl_mime`. * @brief Convert parametermap to `*curl_mime`.
@ -377,4 +371,4 @@ private:
} // namespace mastodonpp } // namespace mastodonpp
#endif // MASTODONPP_CURL_WRAPPER_HPP #endif // MASTODONPP_CURL_WRAPPER_HPP

View File

@ -26,9 +26,9 @@
namespace mastodonpp namespace mastodonpp
{ {
using std::uint16_t;
using std::exception; using std::exception;
using std::string; using std::string;
using std::uint16_t;
/*! /*!
* @brief Exception for libcurl errors. * @brief Exception for libcurl errors.
@ -77,8 +77,7 @@ public:
* *
* @since 0.1.0 * @since 0.1.0
*/ */
[[nodiscard]] [[nodiscard]] const char *what() const noexcept override;
const char *what() const noexcept override;
private: private:
const string _message; const string _message;
@ -87,4 +86,4 @@ private:
} // namespace mastodonpp } // namespace mastodonpp
#endif // MASTODONPP_EXCEPTIONS_HPP #endif // MASTODONPP_EXCEPTIONS_HPP

View File

@ -42,9 +42,8 @@ using std::string;
* *
* @since 0.4.0 * @since 0.4.0
*/ */
[[nodiscard]] [[nodiscard]] string unescape_html(string html);
string unescape_html(string html);
} // namespace mastodonpp } // namespace mastodonpp
#endif // MASTODONPP_HELPERS_HPP #endif // MASTODONPP_HELPERS_HPP

View File

@ -29,10 +29,9 @@
namespace mastodonpp namespace mastodonpp
{ {
using std::uint64_t;
using std::string; using std::string;
using std::string_view; using std::string_view;
using std::move; using std::uint64_t;
using std::vector; using std::vector;
/*! /*!
@ -57,20 +56,14 @@ public:
* *
* @since 0.1.0 * @since 0.1.0
*/ */
explicit Instance(const string_view hostname, explicit Instance(string_view hostname, string_view access_token);
const string_view access_token)
: _hostname{hostname}
, _baseuri{"https://" + _hostname}
, _access_token{access_token}
, _max_chars{0}
{}
/*! /*!
* @brief Copy constructor. A new CURLWrapper is constructed. * @brief Copy constructor. A new CURLWrapper is constructed.
* *
* @since 0.5.2 * @since 0.5.2
*/ */
Instance(const Instance &other) = default; Instance(const Instance &other);
//! Move constructor //! Move constructor
Instance(Instance &&other) noexcept = delete; Instance(Instance &&other) noexcept = delete;
@ -79,10 +72,10 @@ public:
~Instance() noexcept override = default; ~Instance() noexcept override = default;
//! Copy assignment operator //! Copy assignment operator
Instance& operator=(const Instance &other) = delete; Instance &operator=(const Instance &other) = delete;
//! Move assignment operator //! Move assignment operator
Instance& operator=(Instance &&other) noexcept = delete; Instance &operator=(Instance &&other) noexcept = delete;
/*! /*!
* @brief Set the properties of the connection of the calling class up. * @brief Set the properties of the connection of the calling class up.
@ -105,8 +98,7 @@ public:
* *
* @since 0.1.0 * @since 0.1.0
*/ */
[[nodiscard]] [[nodiscard]] inline string_view get_hostname() const noexcept
inline string_view get_hostname() const noexcept
{ {
return _hostname; return _hostname;
} }
@ -118,8 +110,7 @@ public:
* *
* @since 0.1.0 * @since 0.1.0
*/ */
[[nodiscard]] [[nodiscard]] inline string_view get_baseuri() const noexcept
inline string_view get_baseuri() const noexcept
{ {
return _baseuri; return _baseuri;
} }
@ -129,8 +120,7 @@ public:
* *
* @since 0.1.0 * @since 0.1.0
*/ */
[[nodiscard]] [[nodiscard]] inline string_view get_access_token() const noexcept
inline string_view get_access_token() const noexcept
{ {
return _access_token; return _access_token;
} }
@ -143,9 +133,10 @@ public:
* *
* @since 0.1.0 * @since 0.1.0
*/ */
inline void set_access_token(string access_token) inline void set_access_token(const string_view access_token)
{ {
_access_token = move(access_token); _access_token = access_token;
CURLWrapper::set_access_token(access_token);
} }
/*! /*!
@ -159,8 +150,7 @@ public:
* *
* @since 0.1.0 * @since 0.1.0
*/ */
[[nodiscard]] [[nodiscard]] uint64_t get_max_chars() noexcept;
uint64_t get_max_chars() noexcept;
/*! @copydoc CURLWrapper::set_proxy(string_view) /*! @copydoc CURLWrapper::set_proxy(string_view)
* *
@ -182,8 +172,7 @@ public:
* *
* @since 0.3.0 * @since 0.3.0
*/ */
[[nodiscard]] [[nodiscard]] answer_type get_nodeinfo();
answer_type get_nodeinfo();
/*! /*!
* @brief Returns the allowed mime types for statuses. * @brief Returns the allowed mime types for statuses.
@ -277,6 +266,9 @@ public:
* The `body` of the returned @link answer_type answer @endlink * The `body` of the returned @link answer_type answer @endlink
* contains only the URI, not the whole JSON response. * contains only the URI, not the whole JSON response.
* *
* Note that the required scopes may be different between Mastodon and
* other implementations, like Pleroma.
*
* @param client_name The name of your application. * @param client_name The name of your application.
* @param scopes Space separated list of scopes. Defaults to * @param scopes Space separated list of scopes. Defaults to
* read if empty. * read if empty.
@ -287,9 +279,9 @@ public:
* *
* @since 0.3.0 * @since 0.3.0
*/ */
[[nodiscard]] [[nodiscard]] answer_type step_1(string_view client_name,
answer_type step_1(string_view client_name, string_view scopes, string_view scopes,
string_view website); string_view website);
/*! /*!
* @brief Creates a token via `/oauth/token`. * @brief Creates a token via `/oauth/token`.
@ -306,8 +298,7 @@ public:
* *
* @since 0.3.0 * @since 0.3.0
*/ */
[[nodiscard]] [[nodiscard]] answer_type step_2(string_view code);
answer_type step_2(string_view code);
private: private:
Instance &_instance; Instance &_instance;
@ -330,4 +321,4 @@ private:
} // namespace mastodonpp } // namespace mastodonpp
#endif // MASTODONPP_INSTANCE_HPP #endif // MASTODONPP_INSTANCE_HPP

View File

@ -119,4 +119,4 @@
namespace mastodonpp namespace mastodonpp
{} // namespace mastodonpp {} // namespace mastodonpp
#endif // MASTODONPP_HPP #endif // MASTODONPP_HPP

View File

@ -31,13 +31,13 @@
namespace mastodonpp namespace mastodonpp
{ {
using std::uint8_t;
using std::uint16_t;
using std::map; using std::map;
using std::ostream; using std::ostream;
using std::pair;
using std::string; using std::string;
using std::string_view; using std::string_view;
using std::pair; using std::uint16_t;
using std::uint8_t;
using std::variant; using std::variant;
using std::vector; using std::vector;
@ -60,16 +60,16 @@ using std::vector;
* *
* @since 0.1.0 * @since 0.1.0
*/ */
using parametermap = using parametermap = map<string_view,
map<string_view, variant<string_view, vector<string_view>>>; variant<string_view, vector<string_view>>>;
/*! /*!
* @brief A single parameter of a parametermap. * @brief A single parameter of a parametermap.
* *
* @since 0.1.0 * @since 0.1.0
*/ */
using parameterpair = using parameterpair = pair<string_view,
pair<string_view, variant<string_view, vector<string_view>>>; variant<string_view, vector<string_view>>>;
/*! /*!
* @brief Return type for Request%s. * @brief Return type for Request%s.
@ -138,7 +138,7 @@ struct answer_type
* *
* @since 0.1.0 * @since 0.1.0
*/ */
friend ostream &operator <<(ostream &out, const answer_type &answer); friend ostream &operator<<(ostream &out, const answer_type &answer);
/*! /*!
* @brief Returns the value of a header field. * @brief Returns the value of a header field.
@ -149,8 +149,7 @@ struct answer_type
* *
* @since 0.1.0 * @since 0.1.0
*/ */
[[nodiscard]] [[nodiscard]] string_view get_header(string_view field) const;
string_view get_header(string_view field) const;
/*! /*!
* @brief Returns the parameters needed for the next entries. * @brief Returns the parameters needed for the next entries.
@ -159,8 +158,7 @@ struct answer_type
* *
* @since 0.3.0 * @since 0.3.0
*/ */
[[nodiscard]] [[nodiscard]] inline parametermap next() const
inline parametermap next() const
{ {
return parse_pagination(true); return parse_pagination(true);
} }
@ -173,8 +171,7 @@ struct answer_type
* *
* @since 0.3.0 * @since 0.3.0
*/ */
[[nodiscard]] [[nodiscard]] inline parametermap prev() const
inline parametermap prev() const
{ {
return parse_pagination(false); return parse_pagination(false);
} }
@ -188,10 +185,9 @@ private:
* *
* @since 0.3.0 * @since 0.3.0
*/ */
[[nodiscard]] [[nodiscard]] parametermap parse_pagination(bool next) const;
parametermap parse_pagination(bool next) const;
}; };
} // namespace mastodonpp } // namespace mastodonpp
#endif // MASTODONPP_TYPES_HPP #endif // MASTODONPP_TYPES_HPP

View File

@ -25,8 +25,7 @@ API::API(const endpoint_type &endpoint)
// TODO: look for a better way. // TODO: look for a better way.
// NOLINTNEXTLINE(cert-err58-cpp) // NOLINTNEXTLINE(cert-err58-cpp)
const map<API::endpoint_type,string_view> API::_endpoint_map const map<API::endpoint_type, string_view> API::_endpoint_map{
{
{v1::apps, "/api/v1/apps"}, {v1::apps, "/api/v1/apps"},
{v1::apps_verify_credentials, "/api/v1/apps/verify_credentials"}, {v1::apps_verify_credentials, "/api/v1/apps/verify_credentials"},
@ -67,7 +66,7 @@ const map<API::endpoint_type,string_view> API::_endpoint_map
{v1::follow_requests, "/api/v1/follow_requests"}, {v1::follow_requests, "/api/v1/follow_requests"},
{v1::follow_requests_id_authorize, {v1::follow_requests_id_authorize,
"/api/v1/follow_requests/<ID>/authorize"}, "/api/v1/follow_requests/<ID>/authorize"},
{v1::follow_requests_id_reject, "/api/v1/follow_requests/<ID>/reject"}, {v1::follow_requests_id_reject, "/api/v1/follow_requests/<ID>/reject"},
{v1::endorsements, "/api/v1/endorsements"}, {v1::endorsements, "/api/v1/endorsements"},
@ -150,7 +149,7 @@ const map<API::endpoint_type,string_view> API::_endpoint_map
{v1::admin_accounts, "/api/v1/admin/accounts"}, {v1::admin_accounts, "/api/v1/admin/accounts"},
{v1::admin_accounts_id, "/api/v1/admin/accounts/<ID>"}, {v1::admin_accounts_id, "/api/v1/admin/accounts/<ID>"},
{v1::admin_accounts_account_id_action, {v1::admin_accounts_account_id_action,
"/api/v1/admin/accounts/<ACCOUNT_ID>/action"}, "/api/v1/admin/accounts/<ACCOUNT_ID>/action"},
{v1::admin_accounts_id_approve, "/api/v1/admin/accounts/<ID>/approve"}, {v1::admin_accounts_id_approve, "/api/v1/admin/accounts/<ID>/approve"},
{v1::admin_accounts_id_reject, "/api/v1/admin/accounts/<ID>/reject"}, {v1::admin_accounts_id_reject, "/api/v1/admin/accounts/<ID>/reject"},
{v1::admin_accounts_id_enable, "/api/v1/admin/accounts/<ID>/enable"}, {v1::admin_accounts_id_enable, "/api/v1/admin/accounts/<ID>/enable"},
@ -159,39 +158,39 @@ const map<API::endpoint_type,string_view> API::_endpoint_map
{v1::admin_reports, "/api/v1/admin/reports"}, {v1::admin_reports, "/api/v1/admin/reports"},
{v1::admin_reports_id, "/api/v1/admin/reports/<ID>"}, {v1::admin_reports_id, "/api/v1/admin/reports/<ID>"},
{v1::admin_reports_id_assign_to_self, {v1::admin_reports_id_assign_to_self,
"/api/v1/admin/reports/<ID>/assign_to_self"}, "/api/v1/admin/reports/<ID>/assign_to_self"},
{v1::admin_reports_id_unassign, "/api/v1/admin/reports/<ID>/unassign"}, {v1::admin_reports_id_unassign, "/api/v1/admin/reports/<ID>/unassign"},
{v1::admin_reports_id_resolve, "/api/v1/admin/reports/<ID>/resolve"}, {v1::admin_reports_id_resolve, "/api/v1/admin/reports/<ID>/resolve"},
{v1::admin_reports_id_reopen, "/api/v1/admin/reports/<ID>/reopen"}, {v1::admin_reports_id_reopen, "/api/v1/admin/reports/<ID>/reopen"},
{v1::pleroma_notifications_read, " /api/v1/pleroma/notifications/read"}, {v1::pleroma_notifications_read, " /api/v1/pleroma/notifications/read"},
{v1::pleroma_accounts_id_subscribe, {v1::pleroma_accounts_id_subscribe,
"/api/v1/pleroma/accounts/<ID>/subscribe"}, "/api/v1/pleroma/accounts/<ID>/subscribe"},
{v1::pleroma_accounts_id_unsubscribe, {v1::pleroma_accounts_id_unsubscribe,
"/api/v1/pleroma/accounts/<ID>/unsubscribe"}, "/api/v1/pleroma/accounts/<ID>/unsubscribe"},
{v1::pleroma_accounts_id_favourites, {v1::pleroma_accounts_id_favourites,
"/api/v1/pleroma/accounts/<ID>/favourites"}, "/api/v1/pleroma/accounts/<ID>/favourites"},
{v1::pleroma_accounts_update_avatar, {v1::pleroma_accounts_update_avatar,
"/api/v1/pleroma/accounts/update_avatar"}, "/api/v1/pleroma/accounts/update_avatar"},
{v1::pleroma_accounts_update_banner, {v1::pleroma_accounts_update_banner,
"/api/v1/pleroma/accounts/update_banner"}, "/api/v1/pleroma/accounts/update_banner"},
{v1::pleroma_accounts_update_background, {v1::pleroma_accounts_update_background,
"/api/v1/pleroma/accounts/update_background"}, "/api/v1/pleroma/accounts/update_background"},
{v1::pleroma_accounts_confirmation_resend, {v1::pleroma_accounts_confirmation_resend,
"/api/v1/pleroma/accounts/confirmation_resend"}, "/api/v1/pleroma/accounts/confirmation_resend"},
{v1::pleroma_mascot, "/api/v1/pleroma/mascot"}, {v1::pleroma_mascot, "/api/v1/pleroma/mascot"},
{v1::pleroma_conversations_id_statuses, {v1::pleroma_conversations_id_statuses,
"/api/v1/pleroma/conversations/<ID>/statuses"}, "/api/v1/pleroma/conversations/<ID>/statuses"},
{v1::pleroma_conversations_id, "/api/v1/pleroma/conversations/<ID>"}, {v1::pleroma_conversations_id, "/api/v1/pleroma/conversations/<ID>"},
{v1::pleroma_conversations_id_read, {v1::pleroma_conversations_id_read,
"/api/v1/pleroma/conversations/<ID>/read"}, "/api/v1/pleroma/conversations/<ID>/read"},
{v1::pleroma_accounts_id_scrobbles, {v1::pleroma_accounts_id_scrobbles,
"/api/v1/pleroma/accounts/<ID>/scrobbles"}, "/api/v1/pleroma/accounts/<ID>/scrobbles"},
{v1::pleroma_scrobble, "/api/v1/pleroma/scrobble"}, {v1::pleroma_scrobble, "/api/v1/pleroma/scrobble"},
{v1::pleroma_statuses_id_reactions_emoji, {v1::pleroma_statuses_id_reactions_emoji,
"/api/v1/pleroma/statuses/<ID>/reactions/<EMOJI>"}, "/api/v1/pleroma/statuses/<ID>/reactions/<EMOJI>"},
{v1::pleroma_statuses_id_reactions, {v1::pleroma_statuses_id_reactions,
"/api/v1/pleroma/statuses/<ID>/reactions"}, "/api/v1/pleroma/statuses/<ID>/reactions"},
{v2::search, "/api/v2/search"}, {v2::search, "/api/v2/search"},
@ -206,64 +205,66 @@ const map<API::endpoint_type,string_view> API::_endpoint_map
{pleroma::admin_users_follow, "/api/pleroma/admin/users/follow"}, {pleroma::admin_users_follow, "/api/pleroma/admin/users/follow"},
{pleroma::admin_users_unfollow, "/api/pleroma/admin/users/unfollow"}, {pleroma::admin_users_unfollow, "/api/pleroma/admin/users/unfollow"},
{pleroma::admin_users_nickname_toggle_activation, {pleroma::admin_users_nickname_toggle_activation,
"/api/pleroma/admin/users/<NICKNAME>/toggle_activation"}, "/api/pleroma/admin/users/<NICKNAME>/toggle_activation"},
{pleroma::admin_users_tag, "/api/pleroma/admin/users/tag"}, {pleroma::admin_users_tag, "/api/pleroma/admin/users/tag"},
{pleroma::admin_users_nickname_permission_group, {pleroma::admin_users_nickname_permission_group,
"/api/pleroma/admin/users/<NICKNAME>/permission_group"}, "/api/pleroma/admin/users/<NICKNAME>/permission_group"},
{pleroma::admin_users_nickname_permission_group_permission_group, {pleroma::admin_users_nickname_permission_group_permission_group,
"/api/pleroma/admin/users/<NICKNAME>" "/api/pleroma/admin/users/<NICKNAME>"
"/permission_group/<PERMISSION_GROUP>"}, "/permission_group/<PERMISSION_GROUP>"},
{pleroma::admin_users_permission_group_permission_group, {pleroma::admin_users_permission_group_permission_group,
"/api/pleroma/admin/users/permission_group/<PERMISSION_GROUP>"}, "/api/pleroma/admin/users/permission_group/<PERMISSION_GROUP>"},
{pleroma::admin_users_activate, "/api/pleroma/admin/users/activate"}, {pleroma::admin_users_activate, "/api/pleroma/admin/users/activate"},
{pleroma::admin_users_deactivate, "/api/pleroma/admin/users/deactivate"}, {pleroma::admin_users_deactivate, "/api/pleroma/admin/users/deactivate"},
{pleroma::admin_users_nickname_or_id, {pleroma::admin_users_nickname_or_id,
"/api/pleroma/admin/users/<NICKNAME_OR_ID>"}, "/api/pleroma/admin/users/<NICKNAME_OR_ID>"},
{pleroma::admin_users_nickname_or_id_statuses, {pleroma::admin_users_nickname_or_id_statuses,
"/api/pleroma/admin/users/<NICKNAME_OR_ID>/statuses"}, "/api/pleroma/admin/users/<NICKNAME_OR_ID>/statuses"},
{pleroma::admin_instances_instance_statuses, {pleroma::admin_instances_instance_statuses,
"/api/pleroma/admin/instances/<INSTANCE>/statuses"}, "/api/pleroma/admin/instances/<INSTANCE>/statuses"},
{pleroma::admin_statuses, "/api/pleroma/admin/statuses"}, {pleroma::admin_statuses, "/api/pleroma/admin/statuses"},
{pleroma::admin_relay, "/api/pleroma/admin/relay"}, {pleroma::admin_relay, "/api/pleroma/admin/relay"},
{pleroma::admin_users_invite_token, {pleroma::admin_users_invite_token,
"/api/pleroma/admin/users/invite_token"}, "/api/pleroma/admin/users/invite_token"},
{pleroma::admin_users_invites, "/api/pleroma/admin/users/invites"}, {pleroma::admin_users_invites, "/api/pleroma/admin/users/invites"},
{pleroma::admin_users_revoke_invite, {pleroma::admin_users_revoke_invite,
"/api/pleroma/admin/users/revoke_invite"}, "/api/pleroma/admin/users/revoke_invite"},
{pleroma::admin_users_email_invite, {pleroma::admin_users_email_invite,
"/api/pleroma/admin/users/email_invite"}, "/api/pleroma/admin/users/email_invite"},
{pleroma::admin_users_nickname_password_reset, {pleroma::admin_users_nickname_password_reset,
"/api/pleroma/admin/users/<NICKNAME>/password_reset"}, "/api/pleroma/admin/users/<NICKNAME>/password_reset"},
{pleroma::admin_users_nickname_update_credentials,
"/api/pleroma/admin/users/<NICKNAME>/update_credentials"},
{pleroma::admin_users_force_password_reset, {pleroma::admin_users_force_password_reset,
"/api/pleroma/admin/users/force_password_reset"}, "/api/pleroma/admin/users/force_password_reset"},
{pleroma::admin_reports, "/api/pleroma/admin/reports"}, {pleroma::admin_reports, "/api/pleroma/admin/reports"},
{pleroma::admin_grouped_reports, "/api/pleroma/admin/grouped_reports"}, {pleroma::admin_grouped_reports, "/api/pleroma/admin/grouped_reports"},
{pleroma::admin_reports_id, "/api/pleroma/admin/reports/<ID>"}, {pleroma::admin_reports_id, "/api/pleroma/admin/reports/<ID>"},
{pleroma::admin_reports_id_notes, "/api/pleroma/admin/reports/<ID>/notes"}, {pleroma::admin_reports_id_notes, "/api/pleroma/admin/reports/<ID>/notes"},
{pleroma::admin_reports_report_id_notes_id, {pleroma::admin_reports_report_id_notes_id,
"/api/pleroma/admin/reports/<REPORT_ID>/notes/<ID>"}, "/api/pleroma/admin/reports/<REPORT_ID>/notes/<ID>"},
{pleroma::admin_statuses_id, "/api/pleroma/admin/statuses/<ID>"}, {pleroma::admin_statuses_id, "/api/pleroma/admin/statuses/<ID>"},
{pleroma::admin_restart, "/api/pleroma/admin/restart"}, {pleroma::admin_restart, "/api/pleroma/admin/restart"},
{pleroma::admin_config, "/api/pleroma/admin/config"}, {pleroma::admin_config, "/api/pleroma/admin/config"},
{pleroma::admin_config_descriptions, {pleroma::admin_config_descriptions,
"/api/pleroma/admin/config/descriptions"}, "/api/pleroma/admin/config/descriptions"},
{pleroma::admin_moderation_log, "/api/pleroma/admin/moderation_log"}, {pleroma::admin_moderation_log, "/api/pleroma/admin/moderation_log"},
{pleroma::admin_reload_emoji, "/api/pleroma/admin/reload_emoji"}, {pleroma::admin_reload_emoji, "/api/pleroma/admin/reload_emoji"},
{pleroma::admin_users_confirm_email, {pleroma::admin_users_confirm_email,
"/api/pleroma/admin/users/confirm_email"}, "/api/pleroma/admin/users/confirm_email"},
{pleroma::admin_users_resend_confirm_email, {pleroma::admin_users_resend_confirm_email,
"/api/pleroma/admin/users/resend_confirm_email"}, "/api/pleroma/admin/users/resend_confirm_email"},
{pleroma::admin_stats, "/api/pleroma/admin/stats"}, {pleroma::admin_stats, "/api/pleroma/admin/stats"},
{pleroma::admin_users_nickname, "/api/pleroma/admin/users/<NICKNAME>"}, {pleroma::admin_users_nickname, "/api/pleroma/admin/users/<NICKNAME>"},
{pleroma::admin_users_nickname_activation_status, {pleroma::admin_users_nickname_activation_status,
"/api/pleroma/admin/users/<NICKNAME>/activation_status"}, "/api/pleroma/admin/users/<NICKNAME>/activation_status"},
{pleroma::admin_reports_id_respond, {pleroma::admin_reports_id_respond,
"/api/pleroma/admin/reports/<ID>/respond"}, "/api/pleroma/admin/reports/<ID>/respond"},
{pleroma::admin_config_migrate_to_db, {pleroma::admin_config_migrate_to_db,
"/api/pleroma/admin/config/migrate_to_db"}, "/api/pleroma/admin/config/migrate_to_db"},
{pleroma::admin_config_migrate_from_db, {pleroma::admin_config_migrate_from_db,
"/api/pleroma/admin/config/migrate_from_db"}, "/api/pleroma/admin/config/migrate_from_db"},
{pleroma::emoji, "/api/pleroma/emoji"}, {pleroma::emoji, "/api/pleroma/emoji"},
{pleroma::follow_import, "/api/pleroma/follow_import"}, {pleroma::follow_import, "/api/pleroma/follow_import"},
@ -276,18 +277,16 @@ const map<API::endpoint_type,string_view> API::_endpoint_map
{pleroma::emoji_packs, "/api/pleroma/emoji/packs"}, {pleroma::emoji_packs, "/api/pleroma/emoji/packs"},
{pleroma::emoji_packs_name, "/api/pleroma/emoji/packs/<NAME>"}, {pleroma::emoji_packs_name, "/api/pleroma/emoji/packs/<NAME>"},
{pleroma::emoji_packs_name_update_file, {pleroma::emoji_packs_name_update_file,
"/api/pleroma/emoji/packs/<NAME>/update_file"}, "/api/pleroma/emoji/packs/<NAME>/update_file"},
{pleroma::emoji_packs_name_update_metadata, {pleroma::emoji_packs_name_update_metadata,
"/api/pleroma/emoji/packs/<NAME>/update_metadata"}, "/api/pleroma/emoji/packs/<NAME>/update_metadata"},
{pleroma::emoji_packs_download_from, {pleroma::emoji_packs_download_from,
"/api/pleroma/emoji/packs/download_from"}, "/api/pleroma/emoji/packs/download_from"},
{pleroma::emoji_packs_list_from, {pleroma::emoji_packs_list_from, "/api/pleroma/emoji/packs/list_from"},
"/api/pleroma/emoji/packs/list_from"},
{pleroma::emoji_packs_name_download_shared, {pleroma::emoji_packs_name_download_shared,
"/api/pleroma/emoji/packs/<NAME>/download_shared"}, "/api/pleroma/emoji/packs/<NAME>/download_shared"},
{pleroma::account_register, "/api/pleroma/account/register"}, {pleroma::account_register, "/api/pleroma/account/register"},
}; };
} // namespace mastodonpp } // namespace mastodonpp

View File

@ -25,8 +25,8 @@ string Connection::endpoint_to_uri(const endpoint_variant &endpoint) const
{ {
if (holds_alternative<API::endpoint_type>(endpoint)) if (holds_alternative<API::endpoint_type>(endpoint))
{ {
return string(_baseuri) return string(_baseuri) += API{std::get<API::endpoint_type>(endpoint)}
+= API{std::get<API::endpoint_type>(endpoint)}.to_string_view(); .to_string_view();
} }
return string(_baseuri) += std::get<string_view>(endpoint); return string(_baseuri) += std::get<string_view>(endpoint);
} }
@ -34,43 +34,43 @@ string Connection::endpoint_to_uri(const endpoint_variant &endpoint) const
answer_type Connection::get(const endpoint_variant &endpoint, answer_type Connection::get(const endpoint_variant &endpoint,
const parametermap &parameters) const parametermap &parameters)
{ {
return make_request(http_method::GET, return make_request(http_method::GET, endpoint_to_uri(endpoint),
endpoint_to_uri(endpoint), parameters); parameters);
} }
answer_type Connection::post(const endpoint_variant &endpoint, answer_type Connection::post(const endpoint_variant &endpoint,
const parametermap &parameters) const parametermap &parameters)
{ {
return make_request(http_method::POST, return make_request(http_method::POST, endpoint_to_uri(endpoint),
endpoint_to_uri(endpoint), parameters); parameters);
} }
answer_type Connection::patch(const endpoint_variant &endpoint, answer_type Connection::patch(const endpoint_variant &endpoint,
const parametermap &parameters) const parametermap &parameters)
{ {
return make_request(http_method::PATCH, return make_request(http_method::PATCH, endpoint_to_uri(endpoint),
endpoint_to_uri(endpoint), parameters); parameters);
} }
answer_type Connection::put(const endpoint_variant &endpoint, answer_type Connection::put(const endpoint_variant &endpoint,
const parametermap &parameters) const parametermap &parameters)
{ {
return make_request(http_method::PUT, return make_request(http_method::PUT, endpoint_to_uri(endpoint),
endpoint_to_uri(endpoint), parameters); parameters);
} }
answer_type Connection::del(const endpoint_variant &endpoint, answer_type Connection::del(const endpoint_variant &endpoint,
const parametermap &parameters) const parametermap &parameters)
{ {
return make_request(http_method::DELETE, return make_request(http_method::DELETE, endpoint_to_uri(endpoint),
endpoint_to_uri(endpoint), parameters); parameters);
} }
string Connection::get_new_stream_contents() string Connection::get_new_stream_contents()
{ {
_buffer_mutex.lock(); _buffer_mutex.lock();
auto &buffer{get_buffer()}; auto &buffer{get_buffer()};
const string buffer_copy{buffer}; string buffer_copy{buffer};
buffer.clear(); buffer.clear();
_buffer_mutex.unlock(); _buffer_mutex.unlock();
return buffer_copy; return buffer_copy;

View File

@ -15,6 +15,7 @@
*/ */
#include "curl_wrapper.hpp" #include "curl_wrapper.hpp"
#include "exceptions.hpp" #include "exceptions.hpp"
#include "log.hpp" #include "log.hpp"
#include "version.hpp" #include "version.hpp"
@ -28,15 +29,15 @@
namespace mastodonpp namespace mastodonpp
{ {
using std::any_of;
using std::array; // NOLINT(misc-unused-using-decls)
using std::atomic;
using std::get; using std::get;
using std::holds_alternative; using std::holds_alternative;
using std::any_of;
using std::transform;
using std::array; // NOLINT(misc-unused-using-decls)
using std::atomic;
using std::toupper; using std::toupper;
using std::uint8_t; using std::transform;
using std::uint16_t; using std::uint16_t;
using std::uint8_t;
// No one will ever need more than 65535 connections. 😉 // No one will ever need more than 65535 connections. 😉
static atomic<uint16_t> curlwrapper_instances{0}; static atomic<uint16_t> curlwrapper_instances{0};
@ -55,17 +56,11 @@ void CURLWrapper::init()
} }
CURLWrapper::CURLWrapper() CURLWrapper::CURLWrapper()
: _connection{}
, _curl_buffer_error{}
, _stream_cancelled{false}
{ {
init(); init();
} }
CURLWrapper::CURLWrapper(const CURLWrapper &) CURLWrapper::CURLWrapper(const CURLWrapper &)
: _connection{}
, _curl_buffer_error{}
, _stream_cancelled{false}
{ {
init(); init();
} }
@ -89,7 +84,7 @@ answer_type CURLWrapper::make_request(const http_method &method, string uri,
_curl_buffer_headers.clear(); _curl_buffer_headers.clear();
_curl_buffer_body.clear(); _curl_buffer_body.clear();
CURLcode code; CURLcode code{CURLE_OK};
switch (method) switch (method)
{ {
case http_method::GET: case http_method::GET:
@ -185,7 +180,7 @@ answer_type CURLWrapper::make_request(const http_method &method, string uri,
if (code == CURLE_OK if (code == CURLE_OK
|| (code == CURLE_ABORTED_BY_CALLBACK && _stream_cancelled)) || (code == CURLE_ABORTED_BY_CALLBACK && _stream_cancelled))
{ {
long http_status; // NOLINT(google-runtime-int) long http_status{0}; // NOLINT(google-runtime-int)
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg) // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
curl_easy_getinfo(_connection, CURLINFO_RESPONSE_CODE, &http_status); curl_easy_getinfo(_connection, CURLINFO_RESPONSE_CODE, &http_status);
answer.http_status = static_cast<uint16_t>(http_status); answer.http_status = static_cast<uint16_t>(http_status);
@ -250,11 +245,11 @@ void CURLWrapper::set_access_token(const string_view access_token)
if (code != CURLE_OK) if (code != CURLE_OK)
{ {
throw CURLException{code, "Could not set authorization token.", throw CURLException{code, "Could not set authorization token.",
_curl_buffer_error}; _curl_buffer_error};
} }
#if (LIBCURL_VERSION_NUM < 0x073d00) // libcurl < 7.61.0. #if (LIBCURL_VERSION_NUM < 0x073d00) // libcurl < 7.61.0.
#define CURLAUTH_BEARER CURLAUTH_ANY # define CURLAUTH_BEARER CURLAUTH_ANY
#endif #endif
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-signed-bitwise) // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-signed-bitwise)
@ -262,7 +257,7 @@ void CURLWrapper::set_access_token(const string_view access_token)
if (code != CURLE_OK) if (code != CURLE_OK)
{ {
throw CURLException{code, "Could not set authorization token.", throw CURLException{code, "Could not set authorization token.",
_curl_buffer_error}; _curl_buffer_error};
} }
debuglog << "Set authorization token.\n"; debuglog << "Set authorization token.\n";
@ -280,20 +275,20 @@ void CURLWrapper::set_cainfo(const string_view path)
void CURLWrapper::set_useragent(const string_view useragent) void CURLWrapper::set_useragent(const string_view useragent)
{ {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg) CURLcode code{
CURLcode code{curl_easy_setopt(_connection, CURLOPT_USERAGENT, // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
useragent.data())}; curl_easy_setopt(_connection, CURLOPT_USERAGENT, useragent.data())};
if (code != CURLE_OK) if (code != CURLE_OK)
{ {
throw CURLException{code, "Failed to set User-Agent", throw CURLException{code, "Failed to set User-Agent",
_curl_buffer_error}; _curl_buffer_error};
} }
debuglog << "Set User-Agent to: " << useragent << '\n'; debuglog << "Set User-Agent to: " << useragent << '\n';
} }
size_t CURLWrapper::writer_body(char *data, size_t size, size_t nmemb) size_t CURLWrapper::writer_body(char *data, size_t size, size_t nmemb)
{ {
if(data == nullptr) if (data == nullptr)
{ {
return 0; return 0;
} }
@ -307,7 +302,7 @@ size_t CURLWrapper::writer_body(char *data, size_t size, size_t nmemb)
size_t CURLWrapper::writer_header(char *data, size_t size, size_t nmemb) size_t CURLWrapper::writer_header(char *data, size_t size, size_t nmemb)
{ {
if(data == nullptr) if (data == nullptr)
{ {
return 0; return 0;
} }
@ -317,8 +312,8 @@ size_t CURLWrapper::writer_header(char *data, size_t size, size_t nmemb)
return size * nmemb; return size * nmemb;
} }
int CURLWrapper::progress(void *, curl_off_t , curl_off_t , int CURLWrapper::progress(void *, curl_off_t, curl_off_t, curl_off_t,
curl_off_t , curl_off_t ) curl_off_t) const
{ {
if (_stream_cancelled) if (_stream_cancelled)
{ {
@ -371,21 +366,25 @@ void CURLWrapper::setup_curl()
bool CURLWrapper::replace_parameter_in_uri(string &uri, bool CURLWrapper::replace_parameter_in_uri(string &uri,
const parameterpair &parameter) const parameterpair &parameter)
{ {
static constexpr array replace static constexpr array replace{"id",
{ "nickname",
"id", "nickname", "nickname_or_id", "account_id", "list_id", "nickname_or_id",
"hashtag", "permission_group", "instance", "report_id", "name", "account_id",
"emoji" "list_id",
}; "hashtag",
"permission_group",
"instance",
"report_id",
"name",
"emoji"};
if (any_of(replace.begin(), replace.end(), if (any_of(replace.begin(), replace.end(),
[&parameter](const auto &s) { return s == parameter.first; })) [&parameter](const auto &s) { return s == parameter.first; }))
{ {
const string searchstring{[&parameter] const string searchstring{[&parameter] {
{
string s{"<"}; string s{"<"};
s += parameter.first; s += parameter.first;
transform(s.begin(), s.end(), s.begin(), transform(s.begin(), s.end(), s.begin(),
[](const unsigned char c){ return toupper(c); }); [](const unsigned char c) { return toupper(c); });
return s; return s;
}()}; }()};
const auto pos{uri.find(searchstring)}; const auto pos{uri.find(searchstring)};
@ -441,8 +440,8 @@ void CURLWrapper::add_parameters_to_uri(string &uri,
} }
} }
void CURLWrapper::add_mime_part(curl_mime *mime, void CURLWrapper::add_mime_part(curl_mime *mime, string_view name,
string_view name, string_view data) string_view data)
{ {
curl_mimepart *part{curl_mime_addpart(mime)}; curl_mimepart *part{curl_mime_addpart(mime)};
if (part == nullptr) if (part == nullptr)

View File

@ -21,8 +21,8 @@
namespace mastodonpp namespace mastodonpp
{ {
using std::to_string;
using std::move; using std::move;
using std::to_string;
CURLException::CURLException(const CURLcode &error, string message) CURLException::CURLException(const CURLcode &error, string message)
: error_code{error} : error_code{error}

View File

@ -26,15 +26,15 @@
namespace mastodonpp namespace mastodonpp
{ {
using std::stoul;
using std::codecvt_utf8; using std::codecvt_utf8;
using std::wstring_convert;
using std::map; using std::map;
using std::move;
using std::regex; using std::regex;
using std::regex_search; using std::regex_search;
using std::smatch; using std::smatch;
using std::stoul;
using std::string_view; using std::string_view;
using std::move; using std::wstring_convert;
string unescape_html(string html) string unescape_html(string html)
{ {
@ -43,145 +43,100 @@ string unescape_html(string html)
// Source: https://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_ // Source: https://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_
// entity_references#Character_entity_references_in_HTML // entity_references#Character_entity_references_in_HTML
const map<string_view, char32_t> names const map<string_view, char32_t>
{ names{{"exclamation", 0x0021}, {"quot", 0x0022}, {"percent", 0x0025},
{ "exclamation", 0x0021 }, { "quot", 0x0022 }, {"amp", 0x0026}, {"apos", 0x0027}, {"add", 0x002B},
{ "percent", 0x0025 }, { "amp", 0x0026 }, {"lt", 0x003C}, {"equal", 0x003D}, {"gt", 0x003E},
{ "apos", 0x0027 }, { "add", 0x002B }, {"nbsp", 0x00A0}, {"iexcl", 0x00A1}, {"cent", 0x00A2},
{ "lt", 0x003C }, { "equal", 0x003D }, {"pound", 0x00A3}, {"curren", 0x00A4}, {"yen", 0x00A5},
{ "gt", 0x003E }, { "nbsp", 0x00A0 }, {"brvbar", 0x00A6}, {"sect", 0x00A7}, {"uml", 0x00A8},
{ "iexcl", 0x00A1 }, { "cent", 0x00A2 }, {"copy", 0x00A9}, {"ordf", 0x00AA}, {"laquo", 0x00AB},
{ "pound", 0x00A3 }, { "curren", 0x00A4 }, {"not", 0x00AC}, {"shy", 0x00AD}, {"reg", 0x00AE},
{ "yen", 0x00A5 }, { "brvbar", 0x00A6 }, {"macr", 0x00AF}, {"deg", 0x00B0}, {"plusmn", 0x00B1},
{ "sect", 0x00A7 }, { "uml", 0x00A8 }, {"sup2", 0x00B2}, {"sup3", 0x00B3}, {"acute", 0x00B4},
{ "copy", 0x00A9 }, { "ordf", 0x00AA }, {"micro", 0x00B5}, {"para", 0x00B6}, {"middot", 0x00B7},
{ "laquo", 0x00AB }, { "not", 0x00AC }, {"cedil", 0x00B8}, {"sup1", 0x00B9}, {"ordm", 0x00BA},
{ "shy", 0x00AD }, { "reg", 0x00AE }, {"raquo", 0x00BB}, {"frac14", 0x00BC}, {"frac12", 0x00BD},
{ "macr", 0x00AF }, { "deg", 0x00B0 }, {"frac34", 0x00BE}, {"iquest", 0x00BF}, {"Agrave", 0x00C0},
{ "plusmn", 0x00B1 }, { "sup2", 0x00B2 }, {"Aacute", 0x00C1}, {"Acirc", 0x00C2}, {"Atilde", 0x00C3},
{ "sup3", 0x00B3 }, { "acute", 0x00B4 }, {"Auml", 0x00C4}, {"Aring", 0x00C5}, {"AElig", 0x00C6},
{ "micro", 0x00B5 }, { "para", 0x00B6 }, {"Ccedil", 0x00C7}, {"Egrave", 0x00C8}, {"Eacute", 0x00C9},
{ "middot", 0x00B7 }, { "cedil", 0x00B8 }, {"Ecirc", 0x00CA}, {"Euml", 0x00CB}, {"Igrave", 0x00CC},
{ "sup1", 0x00B9 }, { "ordm", 0x00BA }, {"Iacute", 0x00CD}, {"Icirc", 0x00CE}, {"Iuml", 0x00CF},
{ "raquo", 0x00BB }, { "frac14", 0x00BC }, {"ETH", 0x00D0}, {"Ntilde", 0x00D1}, {"Ograve", 0x00D2},
{ "frac12", 0x00BD }, { "frac34", 0x00BE }, {"Oacute", 0x00D3}, {"Ocirc", 0x00D4}, {"Otilde", 0x00D5},
{ "iquest", 0x00BF }, { "Agrave", 0x00C0 }, {"Ouml", 0x00D6}, {"times", 0x00D7}, {"Oslash", 0x00D8},
{ "Aacute", 0x00C1 }, { "Acirc", 0x00C2 }, {"Ugrave", 0x00D9}, {"Uacute", 0x00DA}, {"Ucirc", 0x00DB},
{ "Atilde", 0x00C3 }, { "Auml", 0x00C4 }, {"Uuml", 0x00DC}, {"Yacute", 0x00DD}, {"THORN", 0x00DE},
{ "Aring", 0x00C5 }, { "AElig", 0x00C6 }, {"szlig", 0x00DF}, {"agrave", 0x00E0}, {"aacute", 0x00E1},
{ "Ccedil", 0x00C7 }, { "Egrave", 0x00C8 }, {"acirc", 0x00E2}, {"atilde", 0x00E3}, {"auml", 0x00E4},
{ "Eacute", 0x00C9 }, { "Ecirc", 0x00CA }, {"aring", 0x00E5}, {"aelig", 0x00E6}, {"ccedil", 0x00E7},
{ "Euml", 0x00CB }, { "Igrave", 0x00CC }, {"egrave", 0x00E8}, {"eacute", 0x00E9}, {"ecirc", 0x00EA},
{ "Iacute", 0x00CD }, { "Icirc", 0x00CE }, {"euml", 0x00EB}, {"igrave", 0x00EC}, {"iacute", 0x00ED},
{ "Iuml", 0x00CF }, { "ETH", 0x00D0 }, {"icirc", 0x00EE}, {"iuml", 0x00EF}, {"eth", 0x00F0},
{ "Ntilde", 0x00D1 }, { "Ograve", 0x00D2 }, {"ntilde", 0x00F1}, {"ograve", 0x00F2}, {"oacute", 0x00F3},
{ "Oacute", 0x00D3 }, { "Ocirc", 0x00D4 }, {"ocirc", 0x00F4}, {"otilde", 0x00F5}, {"ouml", 0x00F6},
{ "Otilde", 0x00D5 }, { "Ouml", 0x00D6 }, {"divide", 0x00F7}, {"oslash", 0x00F8}, {"ugrave", 0x00F9},
{ "times", 0x00D7 }, { "Oslash", 0x00D8 }, {"uacute", 0x00FA}, {"ucirc", 0x00FB}, {"uuml", 0x00FC},
{ "Ugrave", 0x00D9 }, { "Uacute", 0x00DA }, {"yacute", 0x00FD}, {"thorn", 0x00FE}, {"yuml", 0x00FF},
{ "Ucirc", 0x00DB }, { "Uuml", 0x00DC }, {"OElig", 0x0152}, {"oelig", 0x0153}, {"Scaron", 0x0160},
{ "Yacute", 0x00DD }, { "THORN", 0x00DE }, {"scaron", 0x0161}, {"Yuml", 0x0178}, {"fnof", 0x0192},
{ "szlig", 0x00DF }, { "agrave", 0x00E0 }, {"circ", 0x02C6}, {"tilde", 0x02DC}, {"Alpha", 0x0391},
{ "aacute", 0x00E1 }, { "acirc", 0x00E2 }, {"Beta", 0x0392}, {"Gamma", 0x0393}, {"Delta", 0x0394},
{ "atilde", 0x00E3 }, { "auml", 0x00E4 }, {"Epsilon", 0x0395}, {"Zeta", 0x0396}, {"Eta", 0x0397},
{ "aring", 0x00E5 }, { "aelig", 0x00E6 }, {"Theta", 0x0398}, {"Iota", 0x0399}, {"Kappa", 0x039A},
{ "ccedil", 0x00E7 }, { "egrave", 0x00E8 }, {"Lambda", 0x039B}, {"Mu", 0x039C}, {"Nu", 0x039D},
{ "eacute", 0x00E9 }, { "ecirc", 0x00EA }, {"Xi", 0x039E}, {"Omicron", 0x039F}, {"Pi", 0x03A0},
{ "euml", 0x00EB }, { "igrave", 0x00EC }, {"Rho", 0x03A1}, {"Sigma", 0x03A3}, {"Tau", 0x03A4},
{ "iacute", 0x00ED }, { "icirc", 0x00EE }, {"Upsilon", 0x03A5}, {"Phi", 0x03A6}, {"Chi", 0x03A7},
{ "iuml", 0x00EF }, { "eth", 0x00F0 }, {"Psi", 0x03A8}, {"Omega", 0x03A9}, {"alpha", 0x03B1},
{ "ntilde", 0x00F1 }, { "ograve", 0x00F2 }, {"beta", 0x03B2}, {"gamma", 0x03B3}, {"delta", 0x03B4},
{ "oacute", 0x00F3 }, { "ocirc", 0x00F4 }, {"epsilon", 0x03B5}, {"zeta", 0x03B6}, {"eta", 0x03B7},
{ "otilde", 0x00F5 }, { "ouml", 0x00F6 }, {"theta", 0x03B8}, {"iota", 0x03B9}, {"kappa", 0x03BA},
{ "divide", 0x00F7 }, { "oslash", 0x00F8 }, {"lambda", 0x03BB}, {"mu", 0x03BC}, {"nu", 0x03BD},
{ "ugrave", 0x00F9 }, { "uacute", 0x00FA }, {"xi", 0x03BE}, {"omicron", 0x03BF}, {"pi", 0x03C0},
{ "ucirc", 0x00FB }, { "uuml", 0x00FC }, {"rho", 0x03C1}, {"sigmaf", 0x03C2}, {"sigma", 0x03C3},
{ "yacute", 0x00FD }, { "thorn", 0x00FE }, {"tau", 0x03C4}, {"upsilon", 0x03C5}, {"phi", 0x03C6},
{ "yuml", 0x00FF }, { "OElig", 0x0152 }, {"chi", 0x03C7}, {"psi", 0x03C8}, {"omega", 0x03C9},
{ "oelig", 0x0153 }, { "Scaron", 0x0160 }, {"thetasym", 0x03D1}, {"upsih", 0x03D2}, {"piv", 0x03D6},
{ "scaron", 0x0161 }, { "Yuml", 0x0178 }, {"ensp", 0x2002}, {"emsp", 0x2003}, {"thinsp", 0x2009},
{ "fnof", 0x0192 }, { "circ", 0x02C6 }, {"zwnj", 0x200C}, {"zwj", 0x200D}, {"lrm", 0x200E},
{ "tilde", 0x02DC }, { "Alpha", 0x0391 }, {"rlm", 0x200F}, {"ndash", 0x2013}, {"mdash", 0x2014},
{ "Beta", 0x0392 }, { "Gamma", 0x0393 }, {"horbar", 0x2015}, {"lsquo", 0x2018}, {"rsquo", 0x2019},
{ "Delta", 0x0394 }, { "Epsilon", 0x0395 }, {"sbquo", 0x201A}, {"ldquo", 0x201C}, {"rdquo", 0x201D},
{ "Zeta", 0x0396 }, { "Eta", 0x0397 }, {"bdquo", 0x201E}, {"dagger", 0x2020}, {"Dagger", 0x2021},
{ "Theta", 0x0398 }, { "Iota", 0x0399 }, {"bull", 0x2022}, {"hellip", 0x2026}, {"permil", 0x2030},
{ "Kappa", 0x039A }, { "Lambda", 0x039B }, {"prime", 0x2032}, {"Prime", 0x2033}, {"lsaquo", 0x2039},
{ "Mu", 0x039C }, { "Nu", 0x039D }, {"rsaquo", 0x203A}, {"oline", 0x203E}, {"frasl", 0x2044},
{ "Xi", 0x039E }, { "Omicron", 0x039F }, {"euro", 0x20AC}, {"image", 0x2111}, {"weierp", 0x2118},
{ "Pi", 0x03A0 }, { "Rho", 0x03A1 }, {"real", 0x211C}, {"trade", 0x2122}, {"alefsym", 0x2135},
{ "Sigma", 0x03A3 }, { "Tau", 0x03A4 }, {"larr", 0x2190}, {"uarr", 0x2191}, {"rarr", 0x2192},
{ "Upsilon", 0x03A5 }, { "Phi", 0x03A6 }, {"darr", 0x2193}, {"harr", 0x2194}, {"crarr", 0x21B5},
{ "Chi", 0x03A7 }, { "Psi", 0x03A8 }, {"lArr", 0x21D0}, {"uArr", 0x21D1}, {"rArr", 0x21D2},
{ "Omega", 0x03A9 }, { "alpha", 0x03B1 }, {"dArr", 0x21D3}, {"hArr", 0x21D4}, {"forall", 0x2200},
{ "beta", 0x03B2 }, { "gamma", 0x03B3 }, {"part", 0x2202}, {"exist", 0x2203}, {"empty", 0x2205},
{ "delta", 0x03B4 }, { "epsilon", 0x03B5 }, {"nabla", 0x2207}, {"isin", 0x2208}, {"notin", 0x2209},
{ "zeta", 0x03B6 }, { "eta", 0x03B7 }, {"ni", 0x220B}, {"prod", 0x220F}, {"sum", 0x2211},
{ "theta", 0x03B8 }, { "iota", 0x03B9 }, {"minus", 0x2212}, {"lowast", 0x2217}, {"radic", 0x221A},
{ "kappa", 0x03BA }, { "lambda", 0x03BB }, {"prop", 0x221D}, {"infin", 0x221E}, {"ang", 0x2220},
{ "mu", 0x03BC }, { "nu", 0x03BD }, {"and", 0x2227}, {"or", 0x2228}, {"cap", 0x2229},
{ "xi", 0x03BE }, { "omicron", 0x03BF }, {"cup", 0x222A}, {"int", 0x222B}, {"there4", 0x2234},
{ "pi", 0x03C0 }, { "rho", 0x03C1 }, {"sim", 0x223C}, {"cong", 0x2245}, {"asymp", 0x2248},
{ "sigmaf", 0x03C2 }, { "sigma", 0x03C3 }, {"ne", 0x2260}, {"equiv", 0x2261}, {"le", 0x2264},
{ "tau", 0x03C4 }, { "upsilon", 0x03C5 }, {"ge", 0x2265}, {"sub", 0x2282}, {"sup", 0x2283},
{ "phi", 0x03C6 }, { "chi", 0x03C7 }, {"nsub", 0x2284}, {"sube", 0x2286}, {"supe", 0x2287},
{ "psi", 0x03C8 }, { "omega", 0x03C9 }, {"oplus", 0x2295}, {"otimes", 0x2297}, {"perp", 0x22A5},
{ "thetasym", 0x03D1 }, { "upsih", 0x03D2 }, {"sdot", 0x22C5}, {"lceil", 0x2308}, {"rceil", 0x2309},
{ "piv", 0x03D6 }, { "ensp", 0x2002 }, {"lfloor", 0x230A}, {"rfloor", 0x230B}, {"lang", 0x2329},
{ "emsp", 0x2003 }, { "thinsp", 0x2009 }, {"rang", 0x232A}, {"loz", 0x25CA}, {"spades", 0x2660},
{ "zwnj", 0x200C }, { "zwj", 0x200D }, {"clubs", 0x2663}, {"hearts", 0x2665}, {"diams", 0x2666}};
{ "lrm", 0x200E }, { "rlm", 0x200F },
{ "ndash", 0x2013 }, { "mdash", 0x2014 },
{ "horbar", 0x2015 }, { "lsquo", 0x2018 },
{ "rsquo", 0x2019 }, { "sbquo", 0x201A },
{ "ldquo", 0x201C }, { "rdquo", 0x201D },
{ "bdquo", 0x201E }, { "dagger", 0x2020 },
{ "Dagger", 0x2021 }, { "bull", 0x2022 },
{ "hellip", 0x2026 }, { "permil", 0x2030 },
{ "prime", 0x2032 }, { "Prime", 0x2033 },
{ "lsaquo", 0x2039 }, { "rsaquo", 0x203A },
{ "oline", 0x203E }, { "frasl", 0x2044 },
{ "euro", 0x20AC }, { "image", 0x2111 },
{ "weierp", 0x2118 }, { "real", 0x211C },
{ "trade", 0x2122 }, { "alefsym", 0x2135 },
{ "larr", 0x2190 }, { "uarr", 0x2191 },
{ "rarr", 0x2192 }, { "darr", 0x2193 },
{ "harr", 0x2194 }, { "crarr", 0x21B5 },
{ "lArr", 0x21D0 }, { "uArr", 0x21D1 },
{ "rArr", 0x21D2 }, { "dArr", 0x21D3 },
{ "hArr", 0x21D4 }, { "forall", 0x2200 },
{ "part", 0x2202 }, { "exist", 0x2203 },
{ "empty", 0x2205 }, { "nabla", 0x2207 },
{ "isin", 0x2208 }, { "notin", 0x2209 },
{ "ni", 0x220B }, { "prod", 0x220F },
{ "sum", 0x2211 }, { "minus", 0x2212 },
{ "lowast", 0x2217 }, { "radic", 0x221A },
{ "prop", 0x221D }, { "infin", 0x221E },
{ "ang", 0x2220 }, { "and", 0x2227 },
{ "or", 0x2228 }, { "cap", 0x2229 },
{ "cup", 0x222A }, { "int", 0x222B },
{ "there4", 0x2234 }, { "sim", 0x223C },
{ "cong", 0x2245 }, { "asymp", 0x2248 },
{ "ne", 0x2260 }, { "equiv", 0x2261 },
{ "le", 0x2264 }, { "ge", 0x2265 },
{ "sub", 0x2282 }, { "sup", 0x2283 },
{ "nsub", 0x2284 }, { "sube", 0x2286 },
{ "supe", 0x2287 }, { "oplus", 0x2295 },
{ "otimes", 0x2297 }, { "perp", 0x22A5 },
{ "sdot", 0x22C5 }, { "lceil", 0x2308 },
{ "rceil", 0x2309 }, { "lfloor", 0x230A },
{ "rfloor", 0x230B }, { "lang", 0x2329 },
{ "rang", 0x232A }, { "loz", 0x25CA },
{ "spades", 0x2660 }, { "clubs", 0x2663 },
{ "hearts", 0x2665 }, { "diams", 0x2666 }
};
// Used to convert number to utf-8 char. // Used to convert number to utf-8 char.
wstring_convert<codecvt_utf8<char32_t>, char32_t> u8c; wstring_convert<codecvt_utf8<char32_t>, char32_t> u8c;
// Matches numbered entities between 1 and 8 digits, decimal or hexadecimal, // Matches numbered entities between 1 and 8 digits, decimal or hexadecimal,
// or named entities. // or named entities.
const regex re_entity{"&(#(x)?([[:alnum:]]{1,8})" const regex re_entity{"&(#(x)?([[:alnum:]]{1,8})"
"|[^;[:space:][:punct:]]+);"}; "|[^;[:space:][:punct:]]+);"};
smatch match; smatch match;
while (regex_search(buffer, match, re_entity)) while (regex_search(buffer, match, re_entity))
@ -189,8 +144,10 @@ string unescape_html(string html)
output += match.prefix().str(); output += match.prefix().str();
try try
{ {
// clang-format off
const char32_t codepoint{[&match, &names] const char32_t codepoint{[&match, &names]
{ {
// clang-format on
// If it doesn't start with a '#' it is a named entity. // If it doesn't start with a '#' it is a named entity.
if (match[1].str()[0] != '#') if (match[1].str()[0] != '#')
{ {
@ -199,12 +156,12 @@ string unescape_html(string html)
// 'x' after '#' means the number is hexadecimal. // 'x' after '#' means the number is hexadecimal.
if (match[2].length() == 1) if (match[2].length() == 1)
{ {
return static_cast<char32_t>(stoul(match[3].str(), return static_cast<char32_t>(
nullptr, 16)); stoul(match[3].str(), nullptr, 16));
} }
// '#' without 'x' means the number is decimal. // '#' without 'x' means the number is decimal.
return static_cast<char32_t>(stoul(match[3].str(), return static_cast<char32_t>(
nullptr, 10)); stoul(match[3].str(), nullptr, 10));
}()}; }()};
output += u8c.to_bytes(codepoint); output += u8c.to_bytes(codepoint);
} }

View File

@ -15,6 +15,7 @@
*/ */
#include "instance.hpp" #include "instance.hpp"
#include "log.hpp" #include "log.hpp"
#include <algorithm> #include <algorithm>
@ -24,12 +25,35 @@
namespace mastodonpp namespace mastodonpp
{ {
using std::sort;
using std::stoull;
using std::exception; using std::exception;
using std::regex; using std::regex;
using std::regex_search; using std::regex_search;
using std::smatch; using std::smatch;
using std::sort;
using std::stoull;
Instance::Instance(const string_view hostname, const string_view access_token)
: _hostname{hostname}
, _baseuri{"https://" + _hostname}
, _max_chars{0}
{
set_access_token(access_token);
}
Instance::Instance(const Instance &other)
: CURLWrapper{other}
, _hostname{other._hostname}
, _baseuri{other._baseuri}
, _access_token{other._access_token}
, _max_chars{other._max_chars}
, _proxy{other._proxy}
, _post_formats{other._post_formats}
, _cainfo{other._cainfo}
, _useragent{other._useragent}
{
CURLWrapper::setup_connection_properties(_proxy, _access_token, _cainfo,
_useragent);
}
uint64_t Instance::get_max_chars() noexcept uint64_t Instance::get_max_chars() noexcept
{ {
@ -43,16 +67,18 @@ uint64_t Instance::get_max_chars() noexcept
try try
{ {
debuglog << "Querying " << _hostname << " for max_toot_chars…\n"; debuglog << "Querying " << _hostname << " for max_toot_chars…\n";
const auto answer{make_request(http_method::GET, const auto answer{
_baseuri + "/api/v1/instance", {})}; make_request(http_method::GET, _baseuri + "/api/v1/instance", {})};
if (!answer) if (!answer)
{ {
debuglog << "Could not get instance info.\n"; debuglog << "Could not get instance info.\n";
return default_max_chars; return default_max_chars;
} }
// clang-format off
_max_chars = [&answer] _max_chars = [&answer]
{ {
// clang-format on
const regex re_chars{R"("max_toot_chars"\s*:\s*([^"]+))"}; const regex re_chars{R"("max_toot_chars"\s*:\s*([^"]+))"};
smatch match; smatch match;
@ -77,8 +103,8 @@ uint64_t Instance::get_max_chars() noexcept
answer_type Instance::get_nodeinfo() answer_type Instance::get_nodeinfo()
{ {
auto answer{make_request(http_method::GET, auto answer{
_baseuri + "/.well-known/nodeinfo", {})}; make_request(http_method::GET, _baseuri + "/.well-known/nodeinfo", {})};
if (!answer) if (!answer)
{ {
debuglog << "NodeInfo not found.\n"; debuglog << "NodeInfo not found.\n";
@ -154,11 +180,8 @@ answer_type Instance::ObtainToken::step_1(const string_view client_name,
const string_view scopes, const string_view scopes,
const string_view website) const string_view website)
{ {
parametermap parameters parametermap parameters{{"client_name", client_name},
{ {"redirect_uris", "urn:ietf:wg:oauth:2.0:oob"}};
{"client_name", client_name},
{"redirect_uris", "urn:ietf:wg:oauth:2.0:oob"}
};
if (!scopes.empty()) if (!scopes.empty())
{ {
_scopes = scopes; _scopes = scopes;
@ -169,8 +192,8 @@ answer_type Instance::ObtainToken::step_1(const string_view client_name,
parameters.insert({"website", website}); parameters.insert({"website", website});
} }
auto answer{make_request(http_method::POST, _baseuri + "/api/v1/apps", auto answer{
parameters)}; make_request(http_method::POST, _baseuri + "/api/v1/apps", parameters)};
if (answer) if (answer)
{ {
const regex re_id{R"("client_id"\s*:\s*"([^"]+)\")"}; const regex re_id{R"("client_id"\s*:\s*"([^"]+)\")"};
@ -187,9 +210,10 @@ answer_type Instance::ObtainToken::step_1(const string_view client_name,
} }
string uri{_baseuri + "/oauth/authorize?scope=" + escape_url(scopes) string uri{_baseuri + "/oauth/authorize?scope=" + escape_url(scopes)
+ "&response_type=code" + "&response_type=code"
"&redirect_uri=" + escape_url("urn:ietf:wg:oauth:2.0:oob") "&redirect_uri="
+ "&client_id=" + _client_id}; + escape_url("urn:ietf:wg:oauth:2.0:oob")
+ "&client_id=" + _client_id};
if (!website.empty()) if (!website.empty())
{ {
uri += "&website=" + escape_url(website); uri += "&website=" + escape_url(website);
@ -203,21 +227,18 @@ answer_type Instance::ObtainToken::step_1(const string_view client_name,
answer_type Instance::ObtainToken::step_2(const string_view code) answer_type Instance::ObtainToken::step_2(const string_view code)
{ {
parametermap parameters parametermap parameters{{"client_id", _client_id},
{ {"client_secret", _client_secret},
{"client_id", _client_id}, {"redirect_uri", "urn:ietf:wg:oauth:2.0:oob"},
{"client_secret", _client_secret}, {"code", code},
{"redirect_uri", "urn:ietf:wg:oauth:2.0:oob"}, {"grant_type", "authorization_code"}};
{"code", code},
{"grant_type", "client_credentials"}
};
if (!_scopes.empty()) if (!_scopes.empty())
{ {
parameters.insert({"scope", _scopes}); parameters.insert({"scope", _scopes});
} }
auto answer{make_request(http_method::POST, _baseuri + "/oauth/token", auto answer{
parameters)}; make_request(http_method::POST, _baseuri + "/oauth/token", parameters)};
if (answer) if (answer)
{ {
const regex re_token{R"("access_token"\s*:\s*"([^"]+)\")"}; const regex re_token{R"("access_token"\s*:\s*"([^"]+)\")"};

View File

@ -23,13 +23,13 @@
namespace mastodonpp namespace mastodonpp
{ {
using std::cerr; // NOLINT(misc-unused-using-decls) using std::cerr; // NOLINT(misc-unused-using-decls)
using std::string_view; using std::string_view;
//! @private //! @private
constexpr auto shorten_filename(const string_view &filename) constexpr auto shorten_filename(const string_view &filename)
{ {
for (const string_view &dir : {"/src/", "/include/"}) for (const string_view dir : {"/src/", "/include/"})
{ {
const auto pos{filename.rfind(dir)}; const auto pos{filename.rfind(dir)};
if (pos != string_view::npos) if (pos != string_view::npos)
@ -41,17 +41,17 @@ constexpr auto shorten_filename(const string_view &filename)
} }
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define commonlog cerr << '[' << shorten_filename(__FILE__) \ #define commonlog \
<< ':' << __LINE__ << ']' cerr << '[' << shorten_filename(__FILE__) << ':' << __LINE__ << ']'
#ifndef NDEBUG #ifndef NDEBUG
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define debuglog commonlog << " DEBUG: " # define debuglog commonlog << " DEBUG: "
#else #else
#define debuglog false && cerr # define debuglog false && cerr
#endif #endif
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define errorlog commonlog << " ERROR: " #define errorlog commonlog << " ERROR: "
} // namespace mastodonpp } // namespace mastodonpp
#endif // MASTODONPP_LOG_HPP #endif // MASTODONPP_LOG_HPP

View File

@ -1,5 +1,5 @@
/* This file is part of mastodonpp. /* This file is part of mastodonpp.
* Copyright © 2020 tastytea <tastytea@tastytea.de> * Copyright © 2020, 2021 tastytea <tastytea@tastytea.de>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -14,9 +14,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "log.hpp"
#include "types.hpp" #include "types.hpp"
#include "log.hpp"
#include <algorithm> #include <algorithm>
#include <cctype> #include <cctype>
@ -36,7 +37,7 @@ answer_type::operator string_view() const
return body; return body;
} }
std::ostream &operator <<(std::ostream &out, const answer_type &answer) std::ostream &operator<<(std::ostream &out, const answer_type &answer)
{ {
out << answer.body; out << answer.body;
return out; return out;
@ -45,10 +46,11 @@ std::ostream &operator <<(std::ostream &out, const answer_type &answer)
string_view answer_type::get_header(const string_view field) const string_view answer_type::get_header(const string_view field) const
{ {
const string_view searchstring{string(field) += ':'}; const string_view searchstring{string(field) += ':'};
auto it{search(headers.begin(), headers.end(), // clang-format off
searchstring.begin(), searchstring.end(), auto it{search(headers.begin(), headers.end(), searchstring.begin(),
[](unsigned char a, unsigned char b) searchstring.end(), [](unsigned char a, unsigned char b)
{ return tolower(a) == tolower(b); })}; { return tolower(a) == tolower(b); })};
// clang-format on
if (it != headers.end()) if (it != headers.end())
{ {
@ -69,7 +71,7 @@ parametermap answer_type::parse_pagination(const bool next) const
return {}; return {};
} }
const auto direction{next ? R"(rel="next")" : R"(rel="prev")"}; const string_view direction{next ? R"(rel="next")" : R"(rel="prev")"};
auto endpos{link.find(direction)}; auto endpos{link.find(direction)};
endpos = link.rfind('>', endpos); endpos = link.rfind('>', endpos);
auto startpos{link.rfind('?', endpos) + 1}; auto startpos{link.rfind('?', endpos) + 1};

View File

@ -3,11 +3,16 @@ include(CTest)
file(GLOB sources_tests test_*.cpp) file(GLOB sources_tests test_*.cpp)
find_package(Catch2 CONFIG) find_package(Catch2 CONFIG)
if(Catch2_FOUND) # Catch 2.x if(Catch2_FOUND) # Catch 2.x / 3.x
include(Catch) include(Catch)
add_executable(all_tests main.cpp ${sources_tests}) add_executable(all_tests main.cpp ${sources_tests})
target_link_libraries(all_tests if(TARGET Catch2::Catch2WithMain) # Catch 3.x
PRIVATE Catch2::Catch2 ${PROJECT_NAME}) target_link_libraries(all_tests
PRIVATE Catch2::Catch2WithMain ${PROJECT_NAME})
else() # Catch 2.x
target_link_libraries(all_tests
PRIVATE Catch2::Catch2 ${PROJECT_NAME})
endif()
target_include_directories(all_tests PRIVATE "/usr/include/catch2") target_include_directories(all_tests PRIVATE "/usr/include/catch2")
catch_discover_tests(all_tests EXTRA_ARGS "${EXTRA_TEST_ARGS}") catch_discover_tests(all_tests EXTRA_ARGS "${EXTRA_TEST_ARGS}")
else() # Catch 1.x else() # Catch 1.x

View File

@ -1,5 +1,5 @@
/* This file is part of mastodonpp. /* This file is part of mastodonpp.
* Copyright © 2020 tastytea <tastytea@tastytea.de> * Copyright © 2020, 2022 tastytea <tastytea@tastytea.de>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -16,4 +16,9 @@
#define CATCH_CONFIG_MAIN #define CATCH_CONFIG_MAIN
#include <catch.hpp> // catch 3 does not have catch.hpp anymore
#if __has_include(<catch.hpp>)
# include <catch.hpp>
#else
# include <catch_all.hpp>
#endif

View File

@ -1,5 +1,5 @@
/* This file is part of mastodonpp. /* This file is part of mastodonpp.
* Copyright © 2020 tastytea <tastytea@tastytea.de> * Copyright © 2020, 2022 tastytea <tastytea@tastytea.de>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -14,22 +14,26 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "instance.hpp"
#include "connection.hpp" #include "connection.hpp"
#include "instance.hpp"
#include <catch.hpp> // catch 3 does not have catch.hpp anymore
#if __has_include(<catch.hpp>)
# include <catch.hpp>
#else
# include <catch_all.hpp>
#endif
#include <exception> #include <exception>
namespace mastodonpp namespace mastodonpp
{ {
SCENARIO("mastodonpp::Connection.")
SCENARIO ("mastodonpp::Connection.")
{ {
bool exception = false; bool exception = false;
WHEN ("Connection is instantiated.") WHEN("Connection is instantiated.")
{ {
try try
{ {
@ -41,7 +45,7 @@ SCENARIO ("mastodonpp::Connection.")
exception = true; exception = true;
} }
THEN ("No exception is thrown") THEN("No exception is thrown")
{ {
REQUIRE_FALSE(exception); REQUIRE_FALSE(exception);
} }

View File

@ -1,5 +1,5 @@
/* This file is part of mastodonpp. /* This file is part of mastodonpp.
* Copyright © 2020 tastytea <tastytea@tastytea.de> * Copyright © 2020, 2022 tastytea <tastytea@tastytea.de>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -16,7 +16,12 @@
#include "helpers.hpp" #include "helpers.hpp"
#include <catch.hpp> // catch 3 does not have catch.hpp anymore
#if __has_include(<catch.hpp>)
# include <catch.hpp>
#else
# include <catch_all.hpp>
#endif
#include <exception> #include <exception>
#include <string> #include <string>
@ -26,11 +31,11 @@ namespace mastodonpp
using std::string; using std::string;
SCENARIO ("mastodonpp::html_unescape()") SCENARIO("mastodonpp::html_unescape()")
{ {
bool exception = false; bool exception = false;
WHEN ("html_unescape() is called.") WHEN("html_unescape() is called.")
{ {
string result; string result;
try try
@ -42,8 +47,8 @@ SCENARIO ("mastodonpp::html_unescape()")
exception = true; exception = true;
} }
THEN ("No exception is thrown") THEN("No exception is thrown")
AND_THEN("Result is as expected.") AND_THEN("Result is as expected.")
{ {
REQUIRE_FALSE(exception); REQUIRE_FALSE(exception);
REQUIRE(result == "2€ = 2€ = 2€"); REQUIRE(result == "2€ = 2€ = 2€");

View File

@ -1,5 +1,5 @@
/* This file is part of mastodonpp. /* This file is part of mastodonpp.
* Copyright © 2020 tastytea <tastytea@tastytea.de> * Copyright © 2020, 2022 tastytea <tastytea@tastytea.de>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -16,7 +16,12 @@
#include "instance.hpp" #include "instance.hpp"
#include <catch.hpp> // catch 3 does not have catch.hpp anymore
#if __has_include(<catch.hpp>)
# include <catch.hpp>
#else
# include <catch_all.hpp>
#endif
#include <exception> #include <exception>
#include <string> #include <string>
@ -26,11 +31,11 @@ namespace mastodonpp
using std::string; using std::string;
SCENARIO ("mastopp::Instance") SCENARIO("mastopp::Instance")
{ {
bool exception = false; bool exception = false;
WHEN ("Instance is instantiated.") WHEN("Instance is instantiated.")
{ {
try try
{ {
@ -41,13 +46,13 @@ SCENARIO ("mastopp::Instance")
exception = true; exception = true;
} }
THEN ("No exception is thrown") THEN("No exception is thrown")
{ {
REQUIRE_FALSE(exception); REQUIRE_FALSE(exception);
} }
} }
WHEN ("Variables are set.") WHEN("Variables are set.")
{ {
constexpr auto hostname{"likeable.space"}; constexpr auto hostname{"likeable.space"};
constexpr auto proxy{"socks4a://[::1]:9050"}; constexpr auto proxy{"socks4a://[::1]:9050"};
@ -64,10 +69,10 @@ SCENARIO ("mastopp::Instance")
exception = true; exception = true;
} }
THEN ("No exception is thrown") THEN("No exception is thrown")
AND_THEN ("get_access_token() returns the set value.") AND_THEN("get_access_token() returns the set value.")
AND_THEN ("get_hostname() returns the set value.") AND_THEN("get_hostname() returns the set value.")
AND_THEN ("get_baseuri() returns the expected value.") AND_THEN("get_baseuri() returns the expected value.")
{ {
REQUIRE_FALSE(exception); REQUIRE_FALSE(exception);
REQUIRE(instance.get_access_token() == access_token); REQUIRE(instance.get_access_token() == access_token);