├── .editorconfig
├── .gitattributes
├── .github
└── workflows
│ └── main.yml
├── .gitignore
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── Our.Umbraco.GraphQL.sln
├── README.md
├── appveyor.yml
├── build.cmd
├── docs
└── index.md
├── samples
└── Website
│ ├── .gitignore
│ ├── App_Plugins
│ └── Bergmania.OpenStreetMap
│ │ ├── bergmania.openstreetmap.controller.js
│ │ ├── bergmania.openstreetmap.html
│ │ ├── lang
│ │ ├── da-DK.xml
│ │ └── en-US.xml
│ │ ├── lib
│ │ ├── autocomplete
│ │ │ ├── css
│ │ │ │ └── autocomplete.css
│ │ │ └── js
│ │ │ │ ├── autocomplete.js
│ │ │ │ ├── autocomplete.min.js
│ │ │ │ └── autocomplete.umd.min.js
│ │ └── leaflet
│ │ │ ├── images
│ │ │ ├── layers-2x.png
│ │ │ ├── layers.png
│ │ │ ├── marker-icon-2x.png
│ │ │ ├── marker-icon.png
│ │ │ └── marker-shadow.png
│ │ │ ├── leaflet-src.esm.js
│ │ │ ├── leaflet-src.esm.js.map
│ │ │ ├── leaflet-src.js
│ │ │ └── leaflet.css
│ │ └── package.manifest
│ ├── Program.cs
│ ├── Properties
│ └── launchSettings.json
│ ├── Startup.cs
│ ├── Views
│ ├── Blog.cshtml
│ ├── Blogpost.cshtml
│ ├── MacroPartials
│ │ ├── FeaturedProducts.cshtml
│ │ └── LatestBlogposts.cshtml
│ ├── Partials
│ │ ├── CategoryLinks.cshtml
│ │ ├── ContactForm.cshtml
│ │ ├── Grid
│ │ │ ├── Bootstrap3-Fluid.cshtml
│ │ │ ├── Bootstrap3.cshtml
│ │ │ └── Editors
│ │ │ │ ├── Base.cshtml
│ │ │ │ ├── Embed.cshtml
│ │ │ │ ├── Macro.cshtml
│ │ │ │ ├── Media.cshtml
│ │ │ │ ├── Rte.cshtml
│ │ │ │ └── Textstring.cshtml
│ │ ├── Navigation
│ │ │ ├── SubNavigation.cshtml
│ │ │ └── TopNavigation.cshtml
│ │ ├── SectionHeader.cshtml
│ │ └── blocklist
│ │ │ └── default.cshtml
│ ├── Person.cshtml
│ ├── Product.cshtml
│ ├── Products.cshtml
│ ├── _ViewImports.cshtml
│ ├── contact.cshtml
│ ├── contentPage.cshtml
│ ├── home.cshtml
│ ├── master.cshtml
│ └── people.cshtml
│ ├── Website.csproj
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ └── wwwroot
│ ├── css
│ └── umbraco-starterkit-style.css
│ ├── favicon.ico
│ └── scripts
│ └── umbraco-starterkit-app.js
├── src
└── Our.Umbraco.GraphQL
│ ├── Adapters
│ ├── Builders
│ │ └── FieldBuilderExtensions.cs
│ ├── Examine
│ │ ├── Types
│ │ │ ├── ExamineGraphTypeExtensions.cs
│ │ │ ├── ExamineQuery.cs
│ │ │ ├── ExamineSearcherGraphType.cs
│ │ │ ├── ExamineSearcherQuery.cs
│ │ │ ├── SearchResultFieldsGraphType.cs
│ │ │ ├── SearchResultGraphType.cs
│ │ │ ├── SearchResultInterfaceGraphType.cs
│ │ │ ├── SearchResultsGraphType.cs
│ │ │ └── SearchResultsInterfaceGraphType.cs
│ │ └── Visitors
│ │ │ └── ExamineVisitor.cs
│ ├── GraphTypeAdapter.cs
│ ├── IGraphTypeAdapter.cs
│ ├── PublishedContent
│ │ ├── Types
│ │ │ ├── BlockListItemGraphType.cs
│ │ │ ├── ContentVariationGraphType.cs
│ │ │ ├── HtmlEncodedStringGraphType.cs
│ │ │ ├── PublishedContentCompositionGraphType.cs
│ │ │ ├── PublishedContentGraphType.cs
│ │ │ ├── PublishedContentInterfaceGraphType.cs
│ │ │ ├── PublishedContentTypeGraphType.cs
│ │ │ ├── PublishedElementGraphType.cs
│ │ │ ├── PublishedElementInterfaceGraphType.cs
│ │ │ ├── PublishedGraphTypeExtensions.cs
│ │ │ ├── PublishedItemTypeGraphType.cs
│ │ │ ├── PublishedPropertyFieldType.cs
│ │ │ └── UrlModeGraphType.cs
│ │ └── Visitors
│ │ │ └── PublishedContentVisitor.cs
│ ├── Resolvers
│ │ └── FieldResolver.cs
│ ├── Types
│ │ ├── GuidGraphType.cs
│ │ ├── HtmlGraphType.cs
│ │ ├── IdGraphType.cs
│ │ ├── JsonGraphType.cs
│ │ ├── LinkGraphType.cs
│ │ ├── LinkTypeGraphType.cs
│ │ ├── OrderByGraphType.cs
│ │ ├── Relay
│ │ │ ├── ConnectionGraphType.cs
│ │ │ ├── EdgeGraphType.cs
│ │ │ └── PageInfoGraphType.cs
│ │ ├── Resolution
│ │ │ ├── ITypeRegistry.cs
│ │ │ └── TypeRegistry.cs
│ │ └── UdiGraphType.cs
│ └── Visitors
│ │ ├── CompositeGraphVisitor.cs
│ │ ├── GraphVisitor.cs
│ │ └── IGraphVisitor.cs
│ ├── Attributes
│ ├── DefaultValueAttribute.cs
│ ├── DeprecatedAttribute.cs
│ ├── DescriptionAttribute.cs
│ ├── IgnoreAttribute.cs
│ ├── InjectAttribute.cs
│ ├── NameAttribute.cs
│ ├── NonNullAttribute.cs
│ └── NonNullItemAttribute.cs
│ ├── Builders
│ ├── BuiltSchema.cs
│ ├── ISchemaBuilder.cs
│ └── SchemaBuilder.cs
│ ├── Compose
│ ├── GraphQLComponent.cs
│ ├── GraphQLComposer.cs
│ ├── GraphQLPipelineFilter.cs
│ └── GraphQLUmbracoOptionsSetup.cs
│ ├── Composing
│ ├── CompositionExtensions.cs
│ ├── FieldMiddlewareCollection.cs
│ ├── FieldMiddlewareCollectionBuilder.cs
│ ├── GraphVisitorCollection.cs
│ └── GraphVisitorCollectionBuilder.cs
│ ├── Constants.cs
│ ├── FieldMiddleware
│ └── IFieldMiddleware.cs
│ ├── Filters
│ ├── AndFilter.cs
│ ├── ContainsFilter.cs
│ ├── EndsWithFilter.cs
│ ├── EqFilter.cs
│ ├── GtFilter.cs
│ ├── GteFilter.cs
│ ├── IFilter.cs
│ ├── InFilter.cs
│ ├── LtFilter.cs
│ ├── LteFilter.cs
│ ├── NotFilter.cs
│ ├── OrFilter.cs
│ └── StartsWithFilter.cs
│ ├── IUserContext.cs
│ ├── Json
│ └── Converters
│ │ └── InputsConverter.cs
│ ├── Our.Umbraco.GraphQL.csproj
│ ├── Properties
│ └── AssemblyInfo.cs
│ ├── Reflection
│ └── TypeInfoExtensions.cs
│ ├── Resources
│ └── playground.html
│ ├── Types
│ ├── ConnectionExtensions.cs
│ ├── Id.cs
│ ├── Mutation.cs
│ ├── OrderBy.cs
│ ├── OrderByExtensions.cs
│ ├── PublishedContent
│ │ ├── PublishedContentAtRootQuery.cs
│ │ ├── PublishedContentByTypeQuery.cs
│ │ ├── PublishedContentQuery.cs
│ │ └── UmbracoQuery.cs
│ ├── Query.cs
│ ├── Relay
│ │ ├── Connection.cs
│ │ ├── Edge.cs
│ │ └── PageInfo.cs
│ ├── Schema.cs
│ └── SortOrder.cs
│ ├── Web
│ ├── GraphQLServerOptions.cs
│ └── Middleware
│ │ └── GraphQLMiddleware.cs
│ ├── content
│ └── App_Start
│ │ └── GraphQLComponent.cs.pp
│ └── readme.txt
├── test
└── Our.Umbraco.GraphQL.Tests
│ ├── Adapters
│ ├── GraphTypeAdapterTests.cs
│ ├── PublishedContent
│ │ └── Types
│ │ │ ├── LinkTypeGraphTypeTests.cs
│ │ │ ├── PublishedContentCompositionGraphTypeTests.cs
│ │ │ ├── PublishedContentGraphTypeTests.cs
│ │ │ ├── PublishedContentInterfaceGraphTypeTests.cs
│ │ │ ├── PublishedContentTypeGraphTypeTests.cs
│ │ │ ├── PublishedElementGraphTypeTests.cs
│ │ │ ├── PublishedElementInterfaceGraphTypeTests.cs
│ │ │ ├── PublishedItemTypeGraphType.cs
│ │ │ └── UrlModeGraphTypeTests.cs
│ ├── Resolvers
│ │ └── FieldResolverTests.cs
│ ├── Types
│ │ ├── GuidGraphTypeTests.cs
│ │ ├── HtmlGraphTypeTests.cs
│ │ ├── IdGraphTypeTests.cs
│ │ ├── JsonGraphTypeTests.cs
│ │ ├── LinkGraphTypeTests.cs
│ │ ├── LinkTypeGraphTypeTests.cs
│ │ ├── OrderByGraphTypeTests.cs
│ │ ├── Relay
│ │ │ ├── ConnectionGraphTypeTests.cs
│ │ │ ├── EdgeGraphTypeTests.cs
│ │ │ └── PageInfoGraphTypeTests.cs
│ │ ├── Resolution
│ │ │ └── TypeRegistryTests.cs
│ │ └── UdiGraphTypeTests.cs
│ └── Visitors
│ │ └── CompositeGraphVisitorTests.cs
│ ├── Builders
│ └── SchemaBuilderTests.cs
│ ├── Filters
│ ├── EqFilterTests.cs
│ └── FilterTest.cs
│ ├── Json
│ └── InputConverterTests.cs
│ ├── Our.Umbraco.GraphQL.Tests.csproj
│ └── Types
│ ├── ConnectionExtensionsTests.cs
│ ├── IdTests.cs
│ ├── OrderByExtensionsTests.cs
│ └── PublishedContent
│ ├── PublishedContentAtRootQueryTests.cs
│ ├── PublishedContentQueryTests.cs
│ └── UmbracoQueryTests.cs
└── tools
├── .gitignore
├── build.fsx
└── build.fsx.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | # General settings for whole project
4 | [*]
5 | indent_style = space
6 | indent_size = 4
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
12 | # Format specific overrides
13 | [*.md]
14 | trim_trailing_whitespace = false
15 |
16 | [*.{css,js,json,yml}]
17 | indent_style = space
18 | indent_size = 2
19 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: Build and Publish
2 |
3 | on:
4 | workflow_dispatch:
5 | push:
6 | branches: [develop]
7 |
8 | jobs:
9 | build:
10 | env:
11 | NUGET_TOKEN: ${{ secrets.NUGET_TOKEN }}
12 | NUGET_FEED: https://api.nuget.org/v3/index.json
13 | runs-on: windows-latest
14 |
15 | steps:
16 | - uses: actions/checkout@v2
17 | - name: Setup .NET
18 | uses: actions/setup-dotnet@v1
19 | with:
20 | dotnet-version: 6.0.x
21 |
22 | - name: Add Beta source
23 | run: dotnet nuget add source "https://www.myget.org/F/umbracoprereleases/api/v3/index.json" -n "Umbraco Prereleases"
24 |
25 | - name: Build
26 | run: dotnet pack --include-source --include-symbols -p:SymbolPackageFormat=snupkg -c Release src/Our.Umbraco.GraphQL/Our.Umbraco.GraphQL.csproj -o .
27 |
28 | # - name: Test
29 | # run: dotnet test --no-build --verbosity normal
30 |
31 | - name: Publish NuGet
32 | run: dotnet nuget push *.nupkg -s '${{ env.NUGET_FEED }}' -k '${{ env.NUGET_TOKEN }}'
33 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.user
2 | *.suo
3 | *.log
4 | *.swp
5 | *.exe
6 | *.bak
7 | *.orig
8 | *.zip
9 | .vs/
10 | .idea/
11 | /build/
12 | /packages/
13 | /artifacts/
14 | bower_components/
15 | node_modules/
16 | [Bb]in/
17 | [Oo]bj/
18 | CurrentSettings.vssettings
19 | Visual Studio 2017/*
20 | /src/Our.Umbraco.GraphQL/umbraco/config/
21 | /src/Our.Umbraco.GraphQL/umbraco/PartialViewMacros/
22 | /src/Our.Umbraco.GraphQL/umbraco/UmbracoBackOffice/
23 | /src/Our.Umbraco.GraphQL/umbraco/UmbracoInstall/
24 | /src/Our.Umbraco.GraphQL/umbraco/UmbracoWebsite/
25 | /src/Our.Umbraco.GraphQL/wwwroot/umbraco/
26 | /samples/Website/umbraco
27 | /samples/Website/wwwroot/umbraco
28 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change log
2 |
3 | All notable changes to this project will be documented in this file.
4 | This project adheres to [Semantic Versioning](http://semver.org/).
5 |
6 | ## 0.1.0 - 2018-10-12
7 |
8 | - First release
9 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | ## Bug Reports & Feature Requests
4 |
5 | Please use the [issue tracker](https://github.com/rasmusjp/umbraco-graphql/issues) to report any bugs or file feature requests.
6 |
7 | ## Developing
8 |
9 | ### Prerequisites
10 |
11 | - Visual Studio
12 | - IIS Express
13 |
14 | ### Setup
15 |
16 | First build the Solution
17 |
18 | Run the `samples/Website` project, this will start IIS Express listeninng on `http://localhost:49937`
19 |
20 | Install Umbraco with the starter kit, so you have some sample data.
21 |
22 | ### Folder structure
23 |
24 | ```
25 | .
26 | ├── samples # Sample projects
27 | │ └── Website # Sample/development site
28 | ├── src # Source Files
29 | │ └── Our.Umbraco.GraphQL # Main Project
30 | ├── test # Tests Projects
31 | │ └── Our.Umbraco.GraphQL.Tests # Unit Tests
32 | └── tools # Build tools
33 | ```
34 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018 Rasmus John Pedersen
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Our.Umbraco.GraphQL.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.3.32929.385
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{D56E0413-4D79-45DF-BECA-09D6732637F5}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Website", "samples\Website\Website.csproj", "{C2001952-0774-4BFA-AF30-043B3B16D275}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{BE019E17-BF39-443C-8D62-74940D3B6560}"
11 | EndProject
12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Our.Umbraco.GraphQL", "src\Our.Umbraco.GraphQL\Our.Umbraco.GraphQL.csproj", "{59294783-3A17-479B-90C5-A3A2967176DE}"
13 | EndProject
14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Our.Umbraco.GraphQL.Tests", "test\Our.Umbraco.GraphQL.Tests\Our.Umbraco.GraphQL.Tests.csproj", "{9CC632BF-46A8-4BA6-B51F-CDFF3A935974}"
15 | EndProject
16 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{9B941129-D270-4DD7-A43E-CF2808BFDEE7}"
17 | EndProject
18 | Global
19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
20 | Debug|Any CPU = Debug|Any CPU
21 | Release|Any CPU = Release|Any CPU
22 | EndGlobalSection
23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
24 | {C2001952-0774-4BFA-AF30-043B3B16D275}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
25 | {C2001952-0774-4BFA-AF30-043B3B16D275}.Debug|Any CPU.Build.0 = Debug|Any CPU
26 | {C2001952-0774-4BFA-AF30-043B3B16D275}.Release|Any CPU.ActiveCfg = Release|Any CPU
27 | {59294783-3A17-479B-90C5-A3A2967176DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
28 | {59294783-3A17-479B-90C5-A3A2967176DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
29 | {59294783-3A17-479B-90C5-A3A2967176DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
30 | {59294783-3A17-479B-90C5-A3A2967176DE}.Release|Any CPU.Build.0 = Release|Any CPU
31 | {9CC632BF-46A8-4BA6-B51F-CDFF3A935974}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
32 | {9CC632BF-46A8-4BA6-B51F-CDFF3A935974}.Debug|Any CPU.Build.0 = Debug|Any CPU
33 | {9CC632BF-46A8-4BA6-B51F-CDFF3A935974}.Release|Any CPU.ActiveCfg = Release|Any CPU
34 | {9CC632BF-46A8-4BA6-B51F-CDFF3A935974}.Release|Any CPU.Build.0 = Release|Any CPU
35 | EndGlobalSection
36 | GlobalSection(SolutionProperties) = preSolution
37 | HideSolutionNode = FALSE
38 | EndGlobalSection
39 | GlobalSection(NestedProjects) = preSolution
40 | {C2001952-0774-4BFA-AF30-043B3B16D275} = {D56E0413-4D79-45DF-BECA-09D6732637F5}
41 | {59294783-3A17-479B-90C5-A3A2967176DE} = {BE019E17-BF39-443C-8D62-74940D3B6560}
42 | {9CC632BF-46A8-4BA6-B51F-CDFF3A935974} = {9B941129-D270-4DD7-A43E-CF2808BFDEE7}
43 | EndGlobalSection
44 | GlobalSection(ExtensibilityGlobals) = postSolution
45 | SolutionGuid = {E20ED350-4522-4159-8FDC-A80A46E7DD7F}
46 | EndGlobalSection
47 | EndGlobal
48 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # GraphQL for Umbraco
2 |
3 | [](https://www.nuget.org/packages/Our.Umbraco.GraphQL)
4 |
5 | > **NOTE**
6 | > This branch is for the latest version of this plugin that supports Umbraco version **11**.
7 |
8 | For other versions, check out:
9 |
10 | - [v7](https://github.com/umbraco-community/umbraco-graphql/blob/v7/dev/README.md)
11 | - [v8](https://github.com/umbraco-community/umbraco-graphql/blob/v8/dev/README.md)
12 | - [v9](https://github.com/umbraco-community/umbraco-graphql/blob/v9/dev/README.md)
13 | - [v10](https://github.com/umbraco-community/umbraco-graphql/blob/v10/dev/README.md)
14 | - develop - THIS BRANCH
15 |
16 | ## What is this
17 |
18 | An implementation of [GraphQL](https://graphql.org) for Umbraco using [GraphQL for .NET](https://github.com/graphql-dotnet/graphql-dotnet).
19 |
20 | Please note this **should not be used in production**, since there are **no security** and all you data will be **publicly available**.
21 |
22 | ## How does it work
23 |
24 | GraphQL types are dynamically generated for all Umbraco document types (content and media), with all the properties as fields.
25 |
26 | ## Installation
27 |
28 | The preferred way to install GraphQL for Umbraco is through NuGet
29 |
30 | ### Option 1: NuGet
31 |
32 | GraphQL for Umbraco is available as a [NuGet package](https://www.nuget.org/packages/Our.Umbraco.GraphQL).
33 |
34 | To install run the following command in the [Package Manager Console](https://docs.nuget.org/docs/start-here/using-the-package-manager-console)
35 |
36 | ```powershell
37 | PM> Install-Package Our.Umbraco.GraphQL
38 | ```
39 |
40 | ### Option 2: From source
41 |
42 | Clone the repository and run the Website (F5 in Visual Studio), install Umbraco with the starter kit and start exploring the API using the GraphQL Playground by opening `/umbraco/graphql`.
43 |
44 | ## Docs
45 |
46 | The docs can be found [here](docs/index.md)
47 |
48 | ## TODO
49 |
50 | - [x] GraphQL Playground
51 | - [x] Schema Stitching (extending types)
52 | - [x] Metrics
53 | - [x] Published Content
54 | - [ ] Published Media
55 | - [ ] Dictionary
56 | - [ ] Statistics (field usage etc.)
57 | - [ ] Deprecation (Content Types and Properties)
58 | - [ ] API Tokens (OAUTH) with permissions (for content types and properties)
59 | - [ ] Data Types
60 | - [ ] Document Types
61 | - [ ] Media Types
62 | - [ ] Member Types
63 | - [ ] Content
64 | - [ ] Media
65 | - [ ] Members
66 | - [ ] Documentation
67 |
68 | ## Contributing
69 |
70 | Anyone can help make this project better - check out our [Contributing guide](CONTRIBUTING.md)
71 |
72 | ## Authors
73 |
74 | - [Rasmus John Pedersen](https://www.github.com/rasmusjp)
75 |
76 | ## License
77 |
78 | Copyright © 2018 Rasmus John Pedersen
79 |
80 | GraphQL for Umbraco is released under the [MIT License](LICENSE)
81 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | version: '{build}'
2 | os: Visual Studio 2017
3 | shallow_clone: true
4 | init:
5 | - set PATH=C:\Ruby25\bin;%PATH%
6 | - git config --global core.autocrlf input
7 | - git config --global core.longpaths true
8 | install:
9 | - gem install sass
10 | build_script:
11 | build.cmd package
12 | test: off
13 | artifacts:
14 | - path: artifacts\*.nupkg
15 | name: NuGetPackages
16 | deploy: off
17 |
--------------------------------------------------------------------------------
/build.cmd:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 | SETLOCAL EnableDelayedExpansion
3 | CLS
4 |
5 | SET "buildVersion="
6 | IF DEFINED APPVEYOR_BUILD_NUMBER (
7 | SET buildVersion=%APPVEYOR_BUILD_NUMBER%
8 | SET buildVersion=00000!buildVersion!
9 | SET buildVersion=!buildVersion:~-6!
10 | SET buildVersion=build!buildVersion!
11 | ) ELSE (
12 | SET /p versionSuffix="Please enter a version suffix (e.g. alpha001):"
13 | SET buildVersion=!versionSuffix!
14 | )
15 |
16 | SET "target=%*"
17 | IF NOT DEFINED target (
18 | SET "target=default"
19 | )
20 |
21 | dotnet tool install fake-cli --tool-path tools\bin\ --version 5.*
22 | tools\bin\fake.exe run tools\build.fsx --parallel 3 --target %target% -e buildVersion=!buildVersion!
23 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | # Documentation
2 |
3 | ## Configuration
4 |
5 | When installing the [NuGet package](https://www.nuget.org/packages/Our.Umbraco.GraphQL) a new file `App_Start/GraphQLComponent.cs` is added to the project, it contains the bootstrapping code for adding GraphQL to the project and the default configuration
6 |
7 | ```csharp
8 | var path = $"/{_globalSettings.GetUmbracoMvcArea()}/graphql";
9 |
10 | app.UseUmbracoGraphQL(path, _factory, opts =>
11 | {
12 | opts.Debug = HostingEnvironment.IsDevelopmentEnvironment;
13 | opts.EnableMetrics = true;
14 | opts.EnableMiniProfiler = false;
15 | opts.EnablePlayground = true;
16 | });
17 | ```
18 |
19 | The configuration options are:
20 |
21 | | Option | Description |
22 | | -------------------------------- | -------------------------------------------------------------------------------------------------------- |
23 | | CorsPolicyProvider | The Cors Policy Provider |
24 | | Debug | Should exceptions be exposed in the response |
25 | | EnableMetrics | Should metrics be enabled |
26 | | EnableMiniProfiler | Should MiniProfiler be enabled |
27 | | EnablePlayground | Should the GraphQL Playground be enabled |
28 | | PlaygroundSettings | Custom settings for the [GraphQL Playground](https://github.com/prisma-labs/graphql-playground#settings) |
29 | | SetCorsPolicy(CorsPolicy policy) | Sets the Cors Policy |
30 |
31 | ## Default Urls
32 |
33 | | Method | Url | Description |
34 | | ------ | ---------------- | ------------------ |
35 | | GET | /umbraco/graphql | GraphQL Playground |
36 | | POST | /umbraco/graphql | GraphQL endpoint |
37 |
38 | ## Querying
39 |
40 | The Umbraco queries/types can be found under the `umbraco` field.
41 |
42 | ```graphql
43 | {
44 | umbraco {
45 | content {
46 | atRoot {
47 | all {
48 | }
49 | # ... document types are added as fields
50 | }
51 | byId(id: "id") {
52 | }
53 | byType {
54 | # ... document types are added as fields
55 | }
56 | byUrl(url: "url") {
57 | }
58 | }
59 | }
60 | }
61 | ```
62 |
63 | ## Metrics
64 |
65 | [Apollo Tracing](https://github.com/apollographql/apollo-tracing) is enabled by default and is displayed in the GraphQL Playground, it collects the execution time for each field.
66 |
67 | If you need more insight, [Miniprofiler](https://miniprofiler.com/dotnet/) can be enabled by setting the option `EnableMiniprofiler=true`, MiniProfiler is implemented throughout the Umbraco code base and collects a lot of metrics. The data will be accessiblo in the `extensions.miniProfiler` field in the response.
68 |
--------------------------------------------------------------------------------
/samples/Website/App_Plugins/Bergmania.OpenStreetMap/bergmania.openstreetmap.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | Latitude : {{model.value.marker.latitude}},
18 | Longitude : {{model.value.marker.longitude}}
19 |
20 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/samples/Website/App_Plugins/Bergmania.OpenStreetMap/lang/da-DK.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Breddegrad
6 | Længdegrad
7 |
8 |
--------------------------------------------------------------------------------
/samples/Website/App_Plugins/Bergmania.OpenStreetMap/lang/en-US.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Latitude
6 | Longitude
7 |
8 |
--------------------------------------------------------------------------------
/samples/Website/App_Plugins/Bergmania.OpenStreetMap/lib/leaflet/images/layers-2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umbraco-community/umbraco-graphql/0ebb0284dd9b9ef728367cf2deb24e84af8b8c54/samples/Website/App_Plugins/Bergmania.OpenStreetMap/lib/leaflet/images/layers-2x.png
--------------------------------------------------------------------------------
/samples/Website/App_Plugins/Bergmania.OpenStreetMap/lib/leaflet/images/layers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umbraco-community/umbraco-graphql/0ebb0284dd9b9ef728367cf2deb24e84af8b8c54/samples/Website/App_Plugins/Bergmania.OpenStreetMap/lib/leaflet/images/layers.png
--------------------------------------------------------------------------------
/samples/Website/App_Plugins/Bergmania.OpenStreetMap/lib/leaflet/images/marker-icon-2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umbraco-community/umbraco-graphql/0ebb0284dd9b9ef728367cf2deb24e84af8b8c54/samples/Website/App_Plugins/Bergmania.OpenStreetMap/lib/leaflet/images/marker-icon-2x.png
--------------------------------------------------------------------------------
/samples/Website/App_Plugins/Bergmania.OpenStreetMap/lib/leaflet/images/marker-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umbraco-community/umbraco-graphql/0ebb0284dd9b9ef728367cf2deb24e84af8b8c54/samples/Website/App_Plugins/Bergmania.OpenStreetMap/lib/leaflet/images/marker-icon.png
--------------------------------------------------------------------------------
/samples/Website/App_Plugins/Bergmania.OpenStreetMap/lib/leaflet/images/marker-shadow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umbraco-community/umbraco-graphql/0ebb0284dd9b9ef728367cf2deb24e84af8b8c54/samples/Website/App_Plugins/Bergmania.OpenStreetMap/lib/leaflet/images/marker-shadow.png
--------------------------------------------------------------------------------
/samples/Website/App_Plugins/Bergmania.OpenStreetMap/package.manifest:
--------------------------------------------------------------------------------
1 | {
2 | }
--------------------------------------------------------------------------------
/samples/Website/Program.cs:
--------------------------------------------------------------------------------
1 | namespace umbraco10
2 | {
3 | public class Program
4 | {
5 | public static void Main(string[] args)
6 | => CreateHostBuilder(args)
7 | .Build()
8 | .Run();
9 |
10 | public static IHostBuilder CreateHostBuilder(string[] args) =>
11 | Host.CreateDefaultBuilder(args)
12 | .ConfigureUmbracoDefaults()
13 | .ConfigureWebHostDefaults(webBuilder =>
14 | {
15 | webBuilder.UseStaticWebAssets();
16 | webBuilder.UseStartup();
17 | });
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/samples/Website/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/launchsettings.json",
3 | "iisSettings": {
4 | "windowsAuthentication": false,
5 | "anonymousAuthentication": true,
6 | "iisExpress": {
7 | "applicationUrl": "http://localhost:7868",
8 | "sslPort": 44362
9 | }
10 | },
11 | "profiles": {
12 | "IIS Express": {
13 | "commandName": "IISExpress",
14 | "launchBrowser": true,
15 | "environmentVariables": {
16 | "ASPNETCORE_ENVIRONMENT": "Development"
17 | }
18 | },
19 | "Umbraco.Web.UI": {
20 | "commandName": "Project",
21 | "dotnetRunMessages": true,
22 | "launchBrowser": true,
23 | "applicationUrl": "https://localhost:44362;http://localhost:7868",
24 | "environmentVariables": {
25 | "ASPNETCORE_ENVIRONMENT": "Development"
26 | }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/samples/Website/Startup.cs:
--------------------------------------------------------------------------------
1 | namespace umbraco10
2 | {
3 | public class Startup
4 | {
5 | private readonly IWebHostEnvironment _env;
6 | private readonly IConfiguration _config;
7 |
8 | ///
9 | /// Initializes a new instance of the class.
10 | ///
11 | /// The web hosting environment.
12 | /// The configuration.
13 | ///
14 | /// Only a few services are possible to be injected here https://github.com/dotnet/aspnetcore/issues/9337.
15 | ///
16 | public Startup(IWebHostEnvironment webHostEnvironment, IConfiguration config)
17 | {
18 | _env = webHostEnvironment ?? throw new ArgumentNullException(nameof(webHostEnvironment));
19 | _config = config ?? throw new ArgumentNullException(nameof(config));
20 | }
21 |
22 | ///
23 | /// Configures the services.
24 | ///
25 | /// The services.
26 | ///
27 | /// This method gets called by the runtime. Use this method to add services to the container.
28 | /// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940.
29 | ///
30 | public void ConfigureServices(IServiceCollection services)
31 | {
32 | services.AddUmbraco(_env, _config)
33 | .AddBackOffice()
34 | .AddWebsite()
35 | .AddComposers()
36 | .Build();
37 | }
38 |
39 | ///
40 | /// Configures the application.
41 | ///
42 | /// The application builder.
43 | /// The web hosting environment.
44 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
45 | {
46 | if (env.IsDevelopment())
47 | {
48 | app.UseDeveloperExceptionPage();
49 | }
50 |
51 | app.UseUmbraco()
52 | .WithMiddleware(u =>
53 | {
54 | u.UseBackOffice();
55 | u.UseWebsite();
56 | })
57 | .WithEndpoints(u =>
58 | {
59 | u.UseInstallerEndpoints();
60 | u.UseBackOfficeEndpoints();
61 | u.UseWebsiteEndpoints();
62 | });
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/samples/Website/Views/Blog.cshtml:
--------------------------------------------------------------------------------
1 | @using ContentModels = Umbraco.Cms.Web.Common.PublishedModels
2 |
3 | @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage
4 |
5 | @{
6 | Layout = "master.cshtml";
7 | }
8 | @Html.Partial("~/Views/Partials/SectionHeader.cshtml")
9 |
10 |
11 |
12 |
13 | @await Umbraco.RenderMacroAsync("latestBlogposts",
14 | new
15 | {
16 | numberOfPosts = Model.HowManyPostsShouldBeShown,
17 | startNodeId = Model.Id
18 | })
19 |
20 |
21 |
--------------------------------------------------------------------------------
/samples/Website/Views/Blogpost.cshtml:
--------------------------------------------------------------------------------
1 | @using ContentModels = Umbraco.Cms.Web.Common.PublishedModels
2 | @using Microsoft.AspNetCore.Mvc.Rendering
3 | @using Umbraco.Extensions
4 | @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage
5 | @{
6 | Layout = "master.cshtml";
7 | }
8 | @Html.Partial("~/Views/Partials/SectionHeader.cshtml")
9 |
10 |
11 |
12 |
13 |
14 | @Model.CreateDate.ToShortDateString()
15 |
16 | @Html.Partial("~/Views/Partials/CategoryLinks.cshtml", Model.Categories)
17 |
18 |
19 | @Model.Excerpt
20 | @Html.GetGridHtml(Model, "bodyText", "bootstrap3-fluid")
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/samples/Website/Views/MacroPartials/FeaturedProducts.cshtml:
--------------------------------------------------------------------------------
1 | @using Umbraco.Cms.Core.Models.PublishedContent
2 | @using Umbraco.Cms.Core.Routing
3 | @using Umbraco.Cms.Web.Common
4 | @using Umbraco.Extensions
5 | @inherits Umbraco.Cms.Web.Common.Macros.PartialViewMacroPage
6 | @inject UmbracoHelper Umbraco
7 | @inject IPublishedValueFallback PublishedValueFallback
8 | @inject IPublishedUrlProvider PublishedUrlProvider
9 | @*
10 | This snippet lists the items from a Multinode tree picker, using the pickers default settings.
11 | Content Values stored as xml.
12 |
13 | To get it working with any site's data structure, set the selection equal to the property which has the
14 | multinode treepicker (so: replace "PropertyWithPicker" with the alias of your property).
15 | *@
16 |
17 | @{ var selection = Model.Content.Value>(PublishedValueFallback, "PropertyWithPicker").ToArray(); }
18 |
19 |
20 | @foreach (var id in selection)
21 | {
22 | var item = Umbraco.Content(id);
23 |
24 | @item.Name
25 |
26 | }
27 |
28 |
--------------------------------------------------------------------------------
/samples/Website/Views/Partials/CategoryLinks.cshtml:
--------------------------------------------------------------------------------
1 | @model IEnumerable
2 | @foreach (var category in Model)
3 | {
4 |
5 | @category
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/samples/Website/Views/Partials/ContactForm.cshtml:
--------------------------------------------------------------------------------
1 | @using Umbraco.Extensions
2 | @using Umbraco.SampleSite
3 | @model Umbraco.SampleSite.ContactFormViewModel
4 |
5 | @{
6 | var message = TempData["Message"]?.ToString();
7 | }
8 |
--------------------------------------------------------------------------------
/samples/Website/Views/Partials/Grid/Bootstrap3-Fluid.cshtml:
--------------------------------------------------------------------------------
1 | @using System.Web
2 | @using Microsoft.AspNetCore.Html
3 | @using Newtonsoft.Json.Linq
4 | @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage
5 |
6 | @*
7 | Razor helpers located at the bottom of this file
8 | *@
9 |
10 | @if (Model is JObject && Model?.sections is not null)
11 | {
12 | var oneColumn = ((System.Collections.ICollection)Model.sections).Count == 1;
13 |
14 |
15 | @if (oneColumn)
16 | {
17 | foreach (var section in Model.sections)
18 | {
19 |
20 | @foreach (var row in section.rows)
21 | {
22 | renderRow(row);
23 | }
24 |
25 | }
26 | }
27 | else
28 | {
29 |
30 | @foreach (var sec in Model.sections)
31 | {
32 |
33 |
34 | @foreach (var row in sec.rows)
35 | {
36 | renderRow(row);
37 | }
38 |
39 |
40 | }
41 |
42 | }
43 |
44 | }
45 |
46 | @functions{
47 |
48 | private async Task renderRow(dynamic row)
49 | {
50 |
51 |
52 | @foreach (var area in row.areas)
53 | {
54 |
55 |
56 | @foreach (var control in area.controls)
57 | {
58 | if (control?.editor?.view != null)
59 | {
60 | @await Html.PartialAsync("grid/editors/base", (object)control)
61 | }
62 | }
63 |
64 |
65 | }
66 |
67 |
68 | }
69 | }
70 |
71 | @functions{
72 |
73 | public static HtmlString RenderElementAttributes(dynamic contentItem)
74 | {
75 | var attrs = new List();
76 | JObject cfg = contentItem.config;
77 |
78 | if (cfg != null)
79 | {
80 | foreach (JProperty property in cfg.Properties())
81 | {
82 | var propertyValue = HttpUtility.HtmlAttributeEncode(property.Value.ToString());
83 | attrs.Add(property.Name + "=\"" + propertyValue + "\"");
84 | }
85 | }
86 |
87 | JObject style = contentItem.styles;
88 |
89 | if (style != null) {
90 | var cssVals = new List();
91 | foreach (JProperty property in style.Properties())
92 | {
93 | var propertyValue = property.Value.ToString();
94 | if (string.IsNullOrWhiteSpace(propertyValue) == false)
95 | {
96 | cssVals.Add(property.Name + ":" + propertyValue + ";");
97 | }
98 | }
99 |
100 | if (cssVals.Any())
101 | attrs.Add("style='" + HttpUtility.HtmlAttributeEncode(string.Join(" ", cssVals)) + "'");
102 | }
103 |
104 | return new HtmlString(string.Join(" ", attrs));
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/samples/Website/Views/Partials/Grid/Bootstrap3.cshtml:
--------------------------------------------------------------------------------
1 | @using System.Web
2 | @using Microsoft.AspNetCore.Html
3 | @using Newtonsoft.Json.Linq
4 | @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage
5 |
6 | @if (Model is JObject && Model?.sections is not null)
7 | {
8 | var oneColumn = ((System.Collections.ICollection)Model.sections).Count == 1;
9 |
10 |
11 | @if (oneColumn)
12 | {
13 | foreach (var section in Model.sections)
14 | {
15 |
16 | @foreach (var row in section.rows)
17 | {
18 | renderRow(row, true);
19 | }
20 |
21 | }
22 | }
23 | else
24 | {
25 |
26 |
27 | @foreach (var sec in Model.sections)
28 | {
29 |
30 |
31 | @foreach (var row in sec.rows)
32 | {
33 | renderRow(row, false);
34 | }
35 |
36 |
37 | }
38 |
39 |
40 | }
41 |
42 | }
43 |
44 | @functions{
45 |
46 | private async Task renderRow(dynamic row, bool singleColumn)
47 | {
48 |
49 | @if (singleColumn) {
50 | @:
51 | }
52 |
53 | @foreach (var area in row.areas)
54 | {
55 |
56 |
57 | @foreach (var control in area.controls)
58 | {
59 | if (control?.editor?.view != null)
60 | {
61 | @await Html.PartialAsync("grid/editors/base", (object)control)
62 | }
63 | }
64 |
65 |
66 | }
67 |
68 | @if (singleColumn) {
69 | @:
70 | }
71 |
72 | }
73 |
74 | }
75 |
76 | @functions{
77 |
78 | public static HtmlString RenderElementAttributes(dynamic contentItem)
79 | {
80 | var attrs = new List();
81 | JObject cfg = contentItem.config;
82 |
83 | if (cfg != null)
84 | {
85 | foreach (JProperty property in cfg.Properties())
86 | {
87 | var propertyValue = HttpUtility.HtmlAttributeEncode(property.Value.ToString());
88 | attrs.Add(property.Name + "=\"" + propertyValue + "\"");
89 | }
90 | }
91 |
92 | JObject style = contentItem.styles;
93 |
94 | if (style != null)
95 | {
96 | var cssVals = new List();
97 | foreach (JProperty property in style.Properties())
98 | {
99 | var propertyValue = property.Value.ToString();
100 | if (string.IsNullOrWhiteSpace(propertyValue) == false)
101 | {
102 | cssVals.Add(property.Name + ":" + propertyValue + ";");
103 | }
104 | }
105 |
106 | if (cssVals.Any())
107 | attrs.Add("style=\"" + HttpUtility.HtmlAttributeEncode(string.Join(" ", cssVals)) + "\"");
108 | }
109 |
110 | return new HtmlString(string.Join(" ", attrs));
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/samples/Website/Views/Partials/Grid/Editors/Base.cshtml:
--------------------------------------------------------------------------------
1 | @model dynamic
2 |
3 | @try
4 | {
5 | string editor = EditorView(Model);
6 | @await Html.PartialAsync(editor, Model as object)
7 | }
8 | catch (Exception ex)
9 | {
10 | @ex.ToString()
11 | }
12 |
13 | @functions{
14 |
15 | public static string EditorView(dynamic contentItem)
16 | {
17 | string view = contentItem.editor.render != null ? contentItem.editor.render.ToString() : contentItem.editor.view.ToString();
18 | view = view.Replace(".html", ".cshtml");
19 |
20 | if (!view.Contains("/"))
21 | {
22 | view = "grid/editors/" + view;
23 | }
24 |
25 | return view;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/samples/Website/Views/Partials/Grid/Editors/Embed.cshtml:
--------------------------------------------------------------------------------
1 | @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage
2 |
3 | @if (Model is not null)
4 | {
5 | string embedValue = Convert.ToString(Model.value);
6 | embedValue = embedValue.DetectIsJson() ? Model.value.preview : Model.value;
7 |
8 |
9 | @Html.Raw(embedValue)
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/samples/Website/Views/Partials/Grid/Editors/Macro.cshtml:
--------------------------------------------------------------------------------
1 | @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage
2 |
3 | @if (Model?.value is not null)
4 | {
5 | string macroAlias = Model.value.macroAlias.ToString();
6 | var parameters = new Dictionary();
7 | foreach (var mpd in Model.value.macroParamsDictionary)
8 | {
9 | parameters.Add(mpd.Name, mpd.Value);
10 | }
11 |
12 |
13 | @await Umbraco.RenderMacroAsync(macroAlias, parameters)
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/samples/Website/Views/Partials/Grid/Editors/Media.cshtml:
--------------------------------------------------------------------------------
1 | @model dynamic
2 | @using Umbraco.Cms.Core.Media
3 | @using Umbraco.Cms.Core.PropertyEditors.ValueConverters
4 | @inject IImageUrlGenerator ImageUrlGenerator
5 |
6 | @if (Model?.value is not null)
7 | {
8 | var url = Model.value.image;
9 |
10 | if (Model.editor.config != null && Model.editor.config.size != null)
11 | {
12 | if (Model.value.coordinates != null)
13 | {
14 | url = ImageCropperTemplateCoreExtensions.GetCropUrl(
15 | (string)url,
16 | ImageUrlGenerator,
17 | width: (int)Model.editor.config.size.width,
18 | height: (int)Model.editor.config.size.height,
19 | cropAlias: "default",
20 | cropDataSet: new ImageCropperValue
21 | {
22 | Crops = new[]
23 | {
24 | new ImageCropperValue.ImageCropperCrop
25 | {
26 | Alias = "default",
27 | Coordinates = new ImageCropperValue.ImageCropperCropCoordinates
28 | {
29 | X1 = (decimal)Model.value.coordinates.x1,
30 | Y1 = (decimal)Model.value.coordinates.y1,
31 | X2 = (decimal)Model.value.coordinates.x2,
32 | Y2 = (decimal)Model.value.coordinates.y2
33 | }
34 | }
35 | }
36 | });
37 | }
38 | else
39 | {
40 | url = ImageCropperTemplateCoreExtensions.GetCropUrl(
41 | (string)url,
42 | ImageUrlGenerator,
43 | width: (int)Model.editor.config.size.width,
44 | height: (int)Model.editor.config.size.height,
45 | cropDataSet: new ImageCropperValue
46 | {
47 | FocalPoint = new ImageCropperValue.ImageCropperFocalPoint
48 | {
49 | Top = Model.value.focalPoint == null ? 0.5m : Model.value.focalPoint.top,
50 | Left = Model.value.focalPoint == null ? 0.5m : Model.value.focalPoint.left
51 | }
52 | });
53 | }
54 | }
55 |
56 | var altText = Model.value.altText ?? Model.value.caption ?? string.Empty;
57 |
58 |
59 |
60 | if (Model.value.caption != null)
61 | {
62 | @Model.value.caption
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/samples/Website/Views/Partials/Grid/Editors/Rte.cshtml:
--------------------------------------------------------------------------------
1 | @using Umbraco.Cms.Core.Templates
2 | @model dynamic
3 | @inject HtmlLocalLinkParser HtmlLocalLinkParser;
4 | @inject HtmlUrlParser HtmlUrlParser;
5 | @inject HtmlImageSourceParser HtmlImageSourceParser;
6 |
7 | @{
8 | var value = HtmlLocalLinkParser.EnsureInternalLinks(Model?.value.ToString());
9 | value = HtmlUrlParser.EnsureUrls(value);
10 | value = HtmlImageSourceParser.EnsureImageSources(value);
11 | }
12 |
13 | @Html.Raw(value)
14 |
--------------------------------------------------------------------------------
/samples/Website/Views/Partials/Grid/Editors/Textstring.cshtml:
--------------------------------------------------------------------------------
1 | @model dynamic
2 |
3 | @if (Model?.editor.config.markup is not null)
4 | {
5 | string markup = Model.editor.config.markup.ToString();
6 | markup = markup.Replace("#value#", Html.ReplaceLineBreaks((string)Model.value.ToString()).ToString());
7 |
8 | if (Model.editor.config.style != null)
9 | {
10 | markup = markup.Replace("#style#", Model.editor.config.style.ToString());
11 | }
12 |
13 |
14 | @Html.Raw(markup)
15 |
16 | }
17 | else
18 | {
19 |
20 | @Model?.value
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/samples/Website/Views/Partials/Navigation/SubNavigation.cshtml:
--------------------------------------------------------------------------------
1 | @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage
2 | @using Umbraco.Cms.Core.Models.PublishedContent
3 | @using Umbraco.Cms.Core.Routing
4 | @using Umbraco.Extensions
5 |
6 | @inject IPublishedValueFallback PublishedValueFallback
7 | @inject IPublishedUrlProvider PublishedUrlProvider
8 | @{
9 | var siteSection = Model.AncestorOrSelf(2);
10 | var selection = siteSection.Children.Where(x => x.IsVisible(PublishedValueFallback));
11 | }
12 |
13 | @foreach (var item in selection)
14 | {
15 | @item.Name
16 | }
--------------------------------------------------------------------------------
/samples/Website/Views/Partials/Navigation/TopNavigation.cshtml:
--------------------------------------------------------------------------------
1 | @using Umbraco.Cms.Core.Models.PublishedContent
2 | @using Umbraco.Cms.Core.Routing
3 | @using Umbraco.Extensions
4 | @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage
5 | @{
6 | var site = Model.Root();
7 | var selection = site.Children.Where(x => x.IsVisible());
8 | }
9 |
10 | @site.Name
11 | @foreach (var item in selection)
12 | {
13 | @item.Name
14 | }
--------------------------------------------------------------------------------
/samples/Website/Views/Partials/SectionHeader.cshtml:
--------------------------------------------------------------------------------
1 | @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage
2 |
--------------------------------------------------------------------------------
/samples/Website/Views/Partials/blocklist/default.cshtml:
--------------------------------------------------------------------------------
1 | @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage
2 | @{
3 | if (Model?.Any() != true) { return; }
4 | }
5 |
6 | @foreach (var block in Model)
7 | {
8 | if (block?.ContentUdi == null) { continue; }
9 | var data = block.Content;
10 |
11 | @await Html.PartialAsync("blocklist/Components/" + data.ContentType.Alias, block)
12 | }
13 |
14 |
--------------------------------------------------------------------------------
/samples/Website/Views/Person.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | Layout = "master.cshtml";
3 | }
4 | Nothing to see, but we could make a lesson to display a person
--------------------------------------------------------------------------------
/samples/Website/Views/Product.cshtml:
--------------------------------------------------------------------------------
1 | @using Umbraco.Cms.Web.Common.PublishedModels
2 | @using Umbraco.Extensions
3 | @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage
4 | @{
5 | Layout = "master.cshtml";
6 | var defaultCurrency = Model.Parent().DefaultCurrency;
7 | }
8 |
9 | @Html.Partial("~/Views/Partials/SectionHeader.cshtml", Model.Parent)
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
@Model.ProductName
21 |
@defaultCurrency @Model.Price.ToString("F")
22 |
@Model.Description
23 |
24 | Buy
25 |
26 |
27 | @if (Model.Features != null)
28 | {
29 | foreach (var feature in Model.Features)
30 | {
31 |
32 |
@feature.FeatureName
33 | @feature.FeatureDetails
34 |
35 | }
36 | }
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | @Html.GetGridHtml(Model, "bodyText", "bootstrap3-fluid")
46 |
47 |
--------------------------------------------------------------------------------
/samples/Website/Views/Products.cshtml:
--------------------------------------------------------------------------------
1 | @using Umbraco.Cms.Web.Common.PublishedModels;
2 | @using Umbraco.Extensions
3 | @using ContentModels = Umbraco.Cms.Web.Common.PublishedModels;
4 |
5 | @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage
6 |
7 | @{
8 | Layout = "master.cshtml";
9 | }
10 |
11 | @Html.Partial("~/Views/Partials/SectionHeader.cshtml")
12 |
13 |
--------------------------------------------------------------------------------
/samples/Website/Views/_ViewImports.cshtml:
--------------------------------------------------------------------------------
1 | @using Umbraco.Extensions
2 | @using umbraco10
3 | @using Umbraco.Cms.Web.Common.PublishedModels
4 | @using Umbraco.Cms.Web.Common.Views
5 | @using Umbraco.Cms.Core.Models.PublishedContent
6 | @using Microsoft.AspNetCore.Html
7 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
8 | @addTagHelper *, Smidge
9 | @inject Smidge.SmidgeHelper SmidgeHelper
10 |
--------------------------------------------------------------------------------
/samples/Website/Views/contact.cshtml:
--------------------------------------------------------------------------------
1 | @using Umbraco.SampleSite;
2 | @using ContentModels = Umbraco.Cms.Web.Common.PublishedModels
3 | @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage
4 | @{
5 | Layout = "master.cshtml";
6 | }
7 | @Html.Partial("~/Views/Partials/SectionHeader.cshtml")
8 |
9 |
10 |
11 |
12 |
13 |
@Model.MapHeader
14 | @Model.MapCoordinates
15 |
16 |
17 |
18 |
19 |
@Model.ContactFormHeader
20 | @Model.ContactIntro
21 | @{
22 | await Html.RenderPartialAsync("Partials/ContactForm", new ContactFormViewModel());
23 | }
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/samples/Website/Views/contentPage.cshtml:
--------------------------------------------------------------------------------
1 | @using ContentModels = Umbraco.Cms.Web.Common.PublishedModels
2 | @using Umbraco.Extensions
3 | @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage
4 | @{
5 | Layout = "master.cshtml";
6 | }
7 |
8 | @Html.Partial("~/Views/Partials/SectionHeader.cshtml")
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | @Html.Partial("~/Views/Partials/Navigation/SubNavigation.cshtml")
17 |
18 |
19 |
20 |
21 |
22 | @Html.GetGridHtml(Model, "bodyText", "bootstrap3-fluid")
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/samples/Website/Views/home.cshtml:
--------------------------------------------------------------------------------
1 |
2 | @using Umbraco.Extensions
3 | @using Umbraco.Cms.Web.Common.PublishedModels;
4 | @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage
5 | @{
6 | Layout = "master.cshtml";
7 | var backgroundImage = Model.HeroBackgroundImage != null ? Model.HeroBackgroundImage.Url() : String.Empty;
8 | }
9 |
11 |
12 |
@Model.HeroHeader
13 |
@Model.HeroDescription
14 | @if (Model.HeroCtalink != null)
15 | {
16 |
17 | @Model.HeroCtacaption
18 |
19 | }
20 |
21 |
22 |
23 |
24 | @Html.GetGridHtml(Model, "bodyText", "bootstrap3-fluid")
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/samples/Website/Views/master.cshtml:
--------------------------------------------------------------------------------
1 | @using Umbraco.Cms.Web.Common.PublishedModels;
2 | @using Umbraco.Extensions
3 |
4 | @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage
5 | @{
6 | Layout = null;
7 | // Get basic design settings from the homepage
8 | var home = (Home)Model.Root();
9 | var font = home.Font;
10 | var colorTheme = home.ColorTheme;
11 | }
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | @Model.Name - @home.Sitename
20 |
21 |
22 |
23 |
24 | @RenderSection("Header", required: false)
25 |
26 |
27 |
28 |
29 |
30 | @await Html.PartialAsync("~/Views/Partials/Navigation/TopNavigation.cshtml")
31 |
32 |
33 |
34 |
60 |
61 |
62 | @RenderBody()
63 |
64 |
65 |
66 |
67 |
68 |
69 | @home.FooterAddress
70 |
71 |
72 |
73 |
74 |
75 | @*
76 | Wish not to use JQuery?
77 | Insert this method call to load Umbraco Forms client dependencies without JQuery. @Html.RenderUmbracoFormDependencies()
78 | *@
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/samples/Website/Views/people.cshtml:
--------------------------------------------------------------------------------
1 | @using Umbraco.Cms.Web.Common.PublishedModels;
2 | @using Umbraco.Extensions
3 | @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage
4 | @{
5 | Layout = "master.cshtml";
6 | }
7 | @{
8 | void SocialLink(string content, string service)
9 | {
10 | if (!string.IsNullOrEmpty(content))
11 | {
12 | ; //semicolon needed otherwise cannot be resolved
13 | @service
14 | }
15 | }
16 | }
17 |
18 | @Html.Partial("~/Views/Partials/SectionHeader.cshtml")
19 |
20 |
21 |
22 |
23 |
24 |
33 |
34 | @foreach (Person person in Model.Children
())
35 | {
36 |
37 |
38 |
39 |
40 |
@person.Name
41 | @if (!string.IsNullOrEmpty(person.Email))
42 | {
43 |
@person.Email
44 | }
45 |
46 | @{ SocialLink(person.FacebookUsername, "Facebook"); }
47 | @{ SocialLink(person.TwitterUsername, "Twitter"); }
48 | @{ SocialLink(person.LinkedInUsername, "LinkedIn"); }
49 | @{ SocialLink(person.InstagramUsername, "Instagram"); }
50 |
51 |
52 |
53 | }
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/samples/Website/Website.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net6.0
4 | enable
5 | enable
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | true
23 |
24 |
25 |
26 |
27 | false
28 | false
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/samples/Website/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./appsettings-schema.json",
3 | "Serilog": {
4 | "MinimumLevel": {
5 | "Default": "Information"
6 | },
7 | "WriteTo": [
8 | {
9 | "Name": "Async",
10 | "Args": {
11 | "configure": [
12 | {
13 | "Name": "Console"
14 | }
15 | ]
16 | }
17 | }
18 | ]
19 | },
20 | "Umbraco": {
21 | "CMS": {
22 | "Content": {
23 | "MacroErrors": "Throw"
24 | },
25 | "Hosting": {
26 | "Debug": true
27 | },
28 | "RuntimeMinification": {
29 | "UseInMemoryCache": true,
30 | "CacheBuster": "Timestamp"
31 | }
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/samples/Website/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./appsettings-schema.json",
3 | "Serilog": {
4 | "MinimumLevel": {
5 | "Default": "Information",
6 | "Override": {
7 | "Microsoft": "Warning",
8 | "Microsoft.Hosting.Lifetime": "Information",
9 | "System": "Warning"
10 | }
11 | }
12 | },
13 | "GraphQL": {
14 | "Server": {
15 | "Path": "/umbraco/graphql",
16 | "EnableMetrics": false,
17 | "EnablePlayground": true,
18 | "EnableCors": false
19 | //"Complexity": {
20 | // "MaxDepth": null,
21 | // "MaxComplexity": null,
22 | // "FieldImpact": null,
23 | // "MaxRecursionCount": 250
24 | //},
25 | //"Playground": {
26 |
27 | //}
28 | }
29 | },
30 | "Umbraco": {
31 | "CMS": {
32 | "Global": {
33 | "Id": "86da5b07-cc91-4bd3-b90e-35480a43f8e4",
34 | "SanitizeTinyMce": true
35 | },
36 | "Content": {
37 | "AllowEditInvariantFromNonDefault": true,
38 | "ContentVersionCleanupPolicy": {
39 | "EnableCleanup": true
40 | }
41 | }
42 | }
43 | },
44 | "ConnectionStrings": {
45 | "umbracoDbDSN": "Data Source=|DataDirectory|/Umbraco10.sqlite.db;Cache=Shared;Foreign Keys=True;Pooling=True",
46 | "umbracoDbDSN_ProviderName": "Microsoft.Data.Sqlite"
47 | }
48 | }
--------------------------------------------------------------------------------
/samples/Website/wwwroot/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/umbraco-community/umbraco-graphql/0ebb0284dd9b9ef728367cf2deb24e84af8b8c54/samples/Website/wwwroot/favicon.ico
--------------------------------------------------------------------------------
/samples/Website/wwwroot/scripts/umbraco-starterkit-app.js:
--------------------------------------------------------------------------------
1 | !function e(o, r, n) {
2 | function a(l, t) {
3 | if (!r[l]) {
4 | if (!o[l]) {
5 | var s = "function" == typeof require && require;
6 | if (!t && s) return s(l, !0);
7 | if (i) return i(l, !0);
8 | var c = new Error("Cannot find module '" + l + "'");
9 | throw c.code = "MODULE_NOT_FOUND", c
10 | }
11 | var d = r[l] = { exports: {} };
12 | o[l][0].call(d.exports,
13 | function(e) {
14 | var r = o[l][1][e];
15 | return a(r ? r : e)
16 | },
17 | d,
18 | d.exports,
19 | e,
20 | o,
21 | r,
22 | n)
23 | }
24 | return r[l].exports
25 | }
26 |
27 | for (var i = "function" == typeof require && require, l = 0; l < n.length; l++) a(n[l]);
28 | return a
29 | }({
30 | 1: [
31 | function(e, o, r) {
32 | !function() {
33 | "use strict";
34 | $(document).ready(function() {
35 | $(window).bind("scroll",
36 | function() {
37 | var e = 150;
38 | $(window).scrollTop() > e
39 | ? $(".header").addClass("header--fixed")
40 | : $(".header").removeClass("header--fixed")
41 | }), $(".mobile-nav-handler").click(function(e) {
42 | $(".mobile-nav").toggleClass("mobile-nav--open"), $(".header").toggleClass("header--hide"),
43 | $("body").toggleClass("no-scroll"), $("#toggle-nav").toggleClass("active")
44 | }), $(".nav-link").click(function(e) {
45 | $(".mobile-nav").removeClass("mobile-nav--open"), $(".header").removeClass("header--hide"),
46 | $("body").removeClass("no-scroll"), $("#toggle-nav").removeClass("active")
47 | })
48 | })
49 | }()
50 | }, {}
51 | ]
52 | },
53 | {},
54 | [1]);
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/Builders/FieldBuilderExtensions.cs:
--------------------------------------------------------------------------------
1 | using GraphQL.Builders;
2 | using GraphQL.Types;
3 | using Our.Umbraco.GraphQL.Adapters.Types;
4 |
5 | namespace Our.Umbraco.GraphQL.Adapters.Builders
6 | {
7 | public static class FieldBuilderExtensions
8 | {
9 | public static FieldBuilder Metadata(
10 | this FieldBuilder builder, string key, object value)
11 | {
12 | builder.FieldType.Metadata.Add(key, value);
13 | return builder;
14 | }
15 |
16 | public static ConnectionBuilder Metadata(
17 | this ConnectionBuilder builder, string key, object value)
18 | {
19 | builder.FieldType.Metadata.Add(key, value);
20 | return builder;
21 | }
22 |
23 | public static ConnectionBuilder Orderable(
24 | this ConnectionBuilder builder) where TNodeType : IComplexGraphType
25 | {
26 | builder.Argument>>>("orderBy", "");
27 | return builder;
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/Examine/Types/ExamineQuery.cs:
--------------------------------------------------------------------------------
1 | using Our.Umbraco.GraphQL.Attributes;
2 |
3 | namespace Our.Umbraco.GraphQL.Adapters.Examine.Types
4 | {
5 | public class ExamineQuery
6 | {
7 | }
8 |
9 | public class ExtendUmbracoQueryWithExamineQuery
10 | {
11 | [NonNull]
12 | [Description("Query Examine indexes")]
13 | public ExamineQuery Examine([Inject] ExamineQuery query) => query;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/Examine/Types/ExamineSearcherQuery.cs:
--------------------------------------------------------------------------------
1 | namespace Our.Umbraco.GraphQL.Adapters.Examine.Types
2 | {
3 | public class ExamineSearcherQuery
4 | {
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/Examine/Types/SearchResultFieldsGraphType.cs:
--------------------------------------------------------------------------------
1 | using GraphQL.Types;
2 | using System.Collections.Generic;
3 |
4 | namespace Our.Umbraco.GraphQL.Adapters.Examine.Types
5 | {
6 | public class SearchResultFieldsGraphType : ObjectGraphType>>
7 | {
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/Examine/Types/SearchResultGraphType.cs:
--------------------------------------------------------------------------------
1 | using Examine;
2 | using GraphQL.Types;
3 | using Our.Umbraco.GraphQL.Adapters.PublishedContent.Types;
4 | using System;
5 | using System.Collections.Generic;
6 | using Umbraco.Cms.Core.PublishedCache;
7 |
8 | namespace Our.Umbraco.GraphQL.Adapters.Examine.Types
9 | {
10 | public class SearchResultGraphType : ObjectGraphType
11 | {
12 | public SearchResultGraphType(IPublishedSnapshotAccessor snapshotAccessor, string searcherSafeName, IEnumerable fields)
13 | {
14 | Name = $"{searcherSafeName}Result";
15 |
16 | Interface();
17 |
18 | this.AddBuiltInFields(fields == null);
19 |
20 | if (fields != null)
21 | {
22 | foreach (var field in fields)
23 | {
24 | Field().Name(field.SafeName()).Resolve(ctx => ctx.Source.AllValues.TryGetValue(field, out var list) ? string.Join(", ", list) : null);
25 |
26 | if (field == "__NodeId")
27 | {
28 | Field().Name("_ContentNode").Description("The published content associated with the specified __NodeId value")
29 | .Resolve(ctx =>
30 | {
31 | if (!snapshotAccessor.TryGetPublishedSnapshot(out var publishedSnapshot))
32 | {
33 | throw new InvalidOperationException("Wasn't possible to a get a valid Snapshot");
34 | }
35 |
36 | return int.TryParse(ctx.Source.Id, out var id) ? publishedSnapshot.Content.GetById(id) : null;
37 | });
38 | }
39 | }
40 | }
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/Examine/Types/SearchResultInterfaceGraphType.cs:
--------------------------------------------------------------------------------
1 | using Examine;
2 | using GraphQL;
3 | using GraphQL.Types;
4 |
5 | namespace Our.Umbraco.GraphQL.Adapters.Examine.Types
6 | {
7 | [GraphQLMetadata(TypeName)]
8 | public class SearchResultInterfaceGraphType : InterfaceGraphType
9 | {
10 | private const string TypeName = "SearchResult";
11 | public SearchResultInterfaceGraphType()
12 | {
13 | Name = TypeName;
14 |
15 | this.AddBuiltInFields();
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/Examine/Types/SearchResultsGraphType.cs:
--------------------------------------------------------------------------------
1 | using Examine;
2 | using GraphQL.Types;
3 | using System.Collections.Generic;
4 | using Umbraco.Cms.Core.PublishedCache;
5 |
6 | namespace Our.Umbraco.GraphQL.Adapters.Examine.Types
7 | {
8 | public class SearchResultsGraphType : ObjectGraphType
9 | {
10 | public SearchResultsGraphType(IPublishedSnapshotAccessor snapshotAccessor, string searcherSafeName, IEnumerable fields)
11 | {
12 | Name = $"{searcherSafeName}Results";
13 |
14 | Interface();
15 |
16 | this.AddBuiltInFields(snapshotAccessor, searcherSafeName, fields);
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/Examine/Types/SearchResultsInterfaceGraphType.cs:
--------------------------------------------------------------------------------
1 | using Examine;
2 | using GraphQL;
3 | using GraphQL.Types;
4 |
5 | namespace Our.Umbraco.GraphQL.Adapters.Examine.Types
6 | {
7 | [GraphQLMetadata(TypeName)]
8 | public class SearchResultsInterfaceGraphType : InterfaceGraphType
9 | {
10 | private const string TypeName = "SearchResults";
11 | public SearchResultsInterfaceGraphType()
12 | {
13 | Name = TypeName;
14 |
15 | this.AddBuiltInFields();
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/Examine/Visitors/ExamineVisitor.cs:
--------------------------------------------------------------------------------
1 | using Examine;
2 | using GraphQL.Types;
3 | using Our.Umbraco.GraphQL.Adapters.Examine.Types;
4 | using Our.Umbraco.GraphQL.Adapters.Visitors;
5 | using System;
6 | using System.Linq;
7 | using Umbraco.Cms.Core.PublishedCache;
8 |
9 | namespace Our.Umbraco.GraphQL.Adapters.Examine.Visitors
10 | {
11 | public class ExamineVisitor : GraphVisitor
12 | {
13 | private readonly IPublishedSnapshotAccessor _snapshotAccessor;
14 | private readonly IExamineManager _examineManager;
15 | private readonly Lazy _graphTypeAdapter;
16 | private readonly Lazy _visitor;
17 |
18 | public ExamineVisitor(IPublishedSnapshotAccessor snapshotAccessor, IExamineManager examineManager, Lazy graphTypeAdapter, Lazy visitor)
19 | {
20 | _snapshotAccessor = snapshotAccessor;
21 | _examineManager = examineManager;
22 | _graphTypeAdapter = graphTypeAdapter;
23 | _visitor = visitor;
24 | }
25 |
26 | public override void Visit(ISchema schema)
27 | {
28 | var searchers = _examineManager.Indexes.Select(i => i.Searcher).Concat(_examineManager.RegisteredSearchers).ToList();
29 | var examineQuery = (ObjectGraphType)_graphTypeAdapter.Value.Adapt();
30 |
31 | foreach (var searcher in searchers)
32 | {
33 | var loopCaptured = searcher;
34 | var searcherSafeName = searcher.Name.SafeName();
35 | if (searcherSafeName.EndsWith("Searcher")) searcherSafeName = searcherSafeName.Substring(0, searcherSafeName.Length - 8);
36 |
37 | var graphType = new ExamineSearcherGraphType(_snapshotAccessor, loopCaptured, searcherSafeName);
38 | examineQuery.Field().Name(searcherSafeName).Resolve(ctx => new ExamineSearcherQuery());
39 | examineQuery.GetField(searcherSafeName).ResolvedType = graphType;
40 |
41 | _visitor.Value.Visit(graphType);
42 | schema.RegisterType(graphType);
43 | }
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/IGraphTypeAdapter.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using GraphQL.Types;
3 |
4 | namespace Our.Umbraco.GraphQL.Adapters
5 | {
6 | public interface IGraphTypeAdapter
7 | {
8 | IGraphType Adapt();
9 | IGraphType Adapt(TypeInfo typeInfo);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/PublishedContent/Types/BlockListItemGraphType.cs:
--------------------------------------------------------------------------------
1 | using GraphQL.Types;
2 | using Our.Umbraco.GraphQL.Adapters.Types;
3 | using Umbraco.Cms.Core.Models.Blocks;
4 |
5 | namespace Our.Umbraco.GraphQL.Adapters.PublishedContent.Types
6 | {
7 | public class BlockListItemGraphType : ObjectGraphType
8 | {
9 | public BlockListItemGraphType()
10 | {
11 | Name = "BlockListItem";
12 |
13 | Field("content", resolve: ctx => ctx.Source?.Content);
14 | Field("contentUdi", resolve: ctx => ctx.Source?.ContentUdi);
15 | Field("settings", resolve: ctx => ctx.Source?.Settings);
16 | Field("settingsUdi", resolve: ctx => ctx.Source?.SettingsUdi);
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/PublishedContent/Types/ContentVariationGraphType.cs:
--------------------------------------------------------------------------------
1 | using GraphQL;
2 | using GraphQL.Types;
3 | using Umbraco.Cms.Core.Models;
4 |
5 | namespace Our.Umbraco.GraphQL.Adapters.PublishedContent.Types
6 | {
7 | [GraphQLMetadata(TypeName)]
8 | public class ContentVariationGraphType : EnumerationGraphType
9 | {
10 | private const string TypeName = "ContentVariation";
11 |
12 | public ContentVariationGraphType()
13 | {
14 | Name = TypeName;
15 | Description = "Indicates how values can vary.";
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/PublishedContent/Types/HtmlEncodedStringGraphType.cs:
--------------------------------------------------------------------------------
1 | using GraphQL.Language.AST;
2 | using GraphQL.Types;
3 | using Umbraco.Cms.Core.Strings;
4 |
5 | namespace Our.Umbraco.GraphQL.Adapters.PublishedContent.Types
6 | {
7 | public class HtmlEncodedStringGraphType : ScalarGraphType
8 | {
9 | public HtmlEncodedStringGraphType()
10 | {
11 | Name = "HtmlEncodedString";
12 | Description = "A string containing HTML code.";
13 | }
14 |
15 | public override object ParseLiteral(IValue value)
16 | {
17 | if (value is StringValue stringValue)
18 | return ParseValue(stringValue.Value);
19 | return null;
20 | }
21 |
22 | public override object ParseValue(object value)
23 | {
24 | if (value is string stringValue)
25 | return new HtmlEncodedString(stringValue);
26 |
27 | return null;
28 | }
29 |
30 | public override object Serialize(object value)
31 | {
32 | if (value is IHtmlEncodedString htmlString)
33 | return htmlString.ToHtmlString();
34 |
35 | return null;
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/PublishedContent/Types/PublishedContentCompositionGraphType.cs:
--------------------------------------------------------------------------------
1 | using GraphQL;
2 | using Microsoft.AspNetCore.Http;
3 | using Our.Umbraco.GraphQL.Adapters.Types.Resolution;
4 | using Umbraco.Cms.Core.Models;
5 | using Umbraco.Cms.Core.Models.PublishedContent;
6 | using Umbraco.Cms.Core.Routing;
7 | using Umbraco.Cms.Core.Web;
8 | using Umbraco.Extensions;
9 |
10 | namespace Our.Umbraco.GraphQL.Adapters.PublishedContent.Types
11 | {
12 | public class PublishedContentCompositionGraphType : PublishedContentInterfaceGraphType
13 | {
14 | public PublishedContentCompositionGraphType(IContentTypeComposition contentType,
15 | IPublishedContentType publishedContentType, ITypeRegistry typeRegistry,
16 | IUmbracoContextFactory umbracoContextFactory, IPublishedRouter publishedRouter,
17 | IHttpContextAccessor httpContextAccessor)
18 | {
19 | Name = $"{contentType.Alias.ToPascalCase()}Published{contentType.GetItemType()}";
20 |
21 | foreach (var propertyType in contentType.CompositionPropertyTypes)
22 | base.AddField(new PublishedPropertyFieldType(publishedContentType, propertyType, typeRegistry, umbracoContextFactory, publishedRouter, httpContextAccessor));
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/PublishedContent/Types/PublishedContentGraphType.cs:
--------------------------------------------------------------------------------
1 | using GraphQL;
2 | using GraphQL.Types;
3 | using Microsoft.AspNetCore.Http;
4 | using Our.Umbraco.GraphQL.Adapters.Types.Resolution;
5 | using Umbraco.Cms.Core.Models;
6 | using Umbraco.Cms.Core.Models.PublishedContent;
7 | using Umbraco.Cms.Core.Routing;
8 | using Umbraco.Cms.Core.Web;
9 | using Umbraco.Extensions;
10 |
11 | namespace Our.Umbraco.GraphQL.Adapters.PublishedContent.Types
12 | {
13 | public class PublishedContentGraphType : ObjectGraphType
14 | {
15 | public PublishedContentGraphType(IContentTypeComposition contentType,
16 | IPublishedContentType publishedContentType, ITypeRegistry typeRegistry,
17 | IUmbracoContextFactory umbracoContextFactory, IPublishedRouter publishedRouter,
18 | IHttpContextAccessor httpContextAccessor)
19 | {
20 | Name = $"{contentType.Alias.ToPascalCase()}Published{contentType.GetItemType()}";
21 | IsTypeOf = x => ((IPublishedContent)x).ContentType.Alias == contentType.Alias;
22 |
23 | Interface();
24 |
25 | this.AddBuiltInFields();
26 |
27 | foreach (var propertyType in contentType.CompositionPropertyTypes)
28 | base.AddField(new PublishedPropertyFieldType(publishedContentType, propertyType, typeRegistry, umbracoContextFactory, publishedRouter, httpContextAccessor));
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/PublishedContent/Types/PublishedContentInterfaceGraphType.cs:
--------------------------------------------------------------------------------
1 | using GraphQL;
2 | using GraphQL.Types;
3 | using Umbraco.Cms.Core.Models.PublishedContent;
4 |
5 | namespace Our.Umbraco.GraphQL.Adapters.PublishedContent.Types
6 | {
7 | [GraphQLMetadata(TypeName)]
8 | public class PublishedContentInterfaceGraphType : InterfaceGraphType
9 | {
10 | private const string TypeName = "PublishedContent";
11 | public PublishedContentInterfaceGraphType()
12 | {
13 | Name = TypeName;
14 |
15 | this.AddBuiltInFields();
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/PublishedContent/Types/PublishedContentTypeGraphType.cs:
--------------------------------------------------------------------------------
1 | using GraphQL;
2 | using GraphQL.Types;
3 | using Umbraco.Cms.Core.Models.PublishedContent;
4 |
5 | namespace Our.Umbraco.GraphQL.Adapters.PublishedContent.Types
6 | {
7 | [GraphQLMetadata(TypeName)]
8 | public class PublishedContentTypeGraphType : ObjectGraphType
9 | {
10 | private const string TypeName = "PublishedContentType";
11 | public PublishedContentTypeGraphType()
12 | {
13 | Name = TypeName;
14 |
15 | Field>().Name("alias").Resolve(ctx => ctx.Source.Alias);
16 | Field>>().Name("compositionAliases")
17 | .Resolve(ctx => ctx.Source.CompositionAliases);
18 | Field>().Name("itemType").Resolve(ctx => ctx.Source.ItemType);
19 | Field>().Name("variations")
20 | .Resolve(ctx => ctx.Source.Variations);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/PublishedContent/Types/PublishedElementGraphType.cs:
--------------------------------------------------------------------------------
1 | using GraphQL;
2 | using GraphQL.Types;
3 | using Microsoft.AspNetCore.Http;
4 | using Our.Umbraco.GraphQL.Adapters.Types.Resolution;
5 | using Umbraco.Cms.Core.Models;
6 | using Umbraco.Cms.Core.Models.PublishedContent;
7 |
8 | namespace Our.Umbraco.GraphQL.Adapters.PublishedContent.Types
9 | {
10 | public class PublishedElementGraphType : ObjectGraphType
11 | {
12 | public PublishedElementGraphType(IContentTypeComposition contentType,
13 | IPublishedContentType publishedContentType, ITypeRegistry typeRegistry, IHttpContextAccessor httpContextAccessor)
14 | {
15 | Name = $"{contentType.Alias.ToPascalCase()}PublishedElement";
16 | IsTypeOf = x => ((IPublishedElement) x).ContentType.Alias == contentType.Alias;
17 |
18 | Interface();
19 |
20 | this.AddBuiltInFields();
21 |
22 | foreach (var propertyType in contentType.CompositionPropertyTypes)
23 | base.AddField(new PublishedPropertyFieldType(publishedContentType, propertyType, typeRegistry, null, null, httpContextAccessor));
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/PublishedContent/Types/PublishedElementInterfaceGraphType.cs:
--------------------------------------------------------------------------------
1 | using GraphQL;
2 | using GraphQL.Types;
3 | using Umbraco.Cms.Core.Models.PublishedContent;
4 |
5 | namespace Our.Umbraco.GraphQL.Adapters.PublishedContent.Types
6 | {
7 | [GraphQLMetadata(TypeName)]
8 | public class PublishedElementInterfaceGraphType : InterfaceGraphType
9 | {
10 | private const string TypeName = "PublishedElement";
11 | public PublishedElementInterfaceGraphType()
12 | {
13 | Name = TypeName;
14 |
15 | this.AddBuiltInFields();
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/PublishedContent/Types/PublishedItemTypeGraphType.cs:
--------------------------------------------------------------------------------
1 | using GraphQL;
2 | using GraphQL.Types;
3 | using Umbraco.Cms.Core.Models.PublishedContent;
4 |
5 | namespace Our.Umbraco.GraphQL.Adapters.PublishedContent.Types
6 | {
7 | [GraphQLMetadata(TypeName)]
8 | public class PublishedItemTypeGraphType : EnumerationGraphType
9 | {
10 | private const string TypeName = "PublishedItemType";
11 |
12 | public PublishedItemTypeGraphType()
13 | {
14 | Name = TypeName;
15 | Description = "The type of published element.";
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/PublishedContent/Types/UrlModeGraphType.cs:
--------------------------------------------------------------------------------
1 | using GraphQL;
2 | using GraphQL.Types;
3 | using Umbraco.Cms.Core.Models.PublishedContent;
4 |
5 | namespace Our.Umbraco.GraphQL.Adapters.PublishedContent.Types
6 | {
7 | [GraphQLMetadata(TypeName)]
8 | public class UrlModeGraphType : EnumerationGraphType
9 | {
10 | private const string TypeName = "UrlMode";
11 |
12 | public UrlModeGraphType()
13 | {
14 | Name = TypeName;
15 | Description = "Specifies the type of urls that the url provider should produce, Auto is the default.";
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/Resolvers/FieldResolver.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Reflection;
4 | using System.Threading;
5 | using GraphQL;
6 | using GraphQL.Resolvers;
7 | using GraphQL.Types;
8 | using Our.Umbraco.GraphQL.Attributes;
9 |
10 | namespace Our.Umbraco.GraphQL.Adapters.Resolvers
11 | {
12 | public class FieldResolver : IFieldResolver
13 | {
14 | private readonly FieldType _fieldType;
15 | private readonly IServiceProvider _serviceProvider;
16 |
17 | public FieldResolver(FieldType fieldType, IServiceProvider serviceProvider)
18 | {
19 | _fieldType = fieldType ?? throw new ArgumentNullException(nameof(fieldType));
20 | _serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
21 | }
22 |
23 | public object Resolve(IResolveFieldContext context)
24 | {
25 | var memberInfo = _fieldType.GetMetadata(nameof(MemberInfo));
26 | var source = context.Source;
27 | if(source == null || memberInfo.DeclaringType.IsInstanceOfType(source) == false)
28 | source = _serviceProvider.GetService(memberInfo.DeclaringType);
29 |
30 | switch (memberInfo)
31 | {
32 | case FieldInfo fieldInfo:
33 | return fieldInfo.GetValue(source);
34 | case MethodInfo methodInfo:
35 | return CallMethod(methodInfo, source, context);
36 | case PropertyInfo propertyInfo:
37 | return propertyInfo.GetValue(source);
38 | default:
39 | throw new ArgumentOutOfRangeException(nameof(context));
40 | }
41 | }
42 |
43 | private object CallMethod(MethodInfo methodInfo, object source, IResolveFieldContext context)
44 | {
45 | var parameters = methodInfo.GetParameters().ToList();
46 | var arguments = new object[parameters.Count];
47 |
48 | var argumentsIndex = 0;
49 | for (var i = 0; i < parameters.Count; i++)
50 | {
51 | var parameterInfo = parameters[i];
52 | var parameterType = parameterInfo.ParameterType;
53 |
54 | if (parameterInfo.GetCustomAttribute() != null)
55 | {
56 | arguments[i] = _serviceProvider.GetService(parameterType);
57 | continue;
58 | }
59 |
60 | if (parameterInfo.ParameterType == typeof(CancellationToken))
61 | {
62 | arguments[i] = context.CancellationToken;
63 | continue;
64 | }
65 |
66 | var argument = _fieldType.Arguments[argumentsIndex];
67 | argumentsIndex++;
68 |
69 | arguments[i] = context.GetArgument(parameterType, parameterInfo.Name, argument.DefaultValue);
70 | }
71 |
72 | return methodInfo.Invoke(source, arguments);
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/Types/GuidGraphType.cs:
--------------------------------------------------------------------------------
1 | namespace Our.Umbraco.GraphQL.Adapters.Types
2 | {
3 | public class GuidGraphType : global::GraphQL.Types.GuidGraphType
4 | {
5 | public GuidGraphType()
6 | {
7 | Name = "Guid";
8 | Description = "Globally Unique Identifier.";
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/Types/HtmlGraphType.cs:
--------------------------------------------------------------------------------
1 | using System.Web;
2 | using GraphQL.Language.AST;
3 | using GraphQL.Types;
4 | using Microsoft.AspNetCore.Html;
5 |
6 | namespace Our.Umbraco.GraphQL.Adapters.Types
7 | {
8 | public class HtmlGraphType : ScalarGraphType
9 | {
10 | public HtmlGraphType()
11 | {
12 | Name = "HTML";
13 | Description = "A string containing HTML code.";
14 | }
15 |
16 | public override object ParseLiteral(IValue value)
17 | {
18 | if (value is StringValue stringValue)
19 | return ParseValue(stringValue.Value);
20 | return null;
21 | }
22 |
23 | public override object ParseValue(object value)
24 | {
25 | if(value is string stringValue)
26 | return new HtmlString(stringValue);
27 |
28 | return null;
29 | }
30 |
31 | public override object Serialize(object value)
32 | {
33 | if (value is HtmlString htmlString)
34 | return htmlString.ToString();
35 |
36 | return null;
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/Types/IdGraphType.cs:
--------------------------------------------------------------------------------
1 | using GraphQL.Language.AST;
2 | using Our.Umbraco.GraphQL.Types;
3 |
4 | namespace Our.Umbraco.GraphQL.Adapters.Types
5 | {
6 | public class IdGraphType : global::GraphQL.Types.IdGraphType
7 | {
8 | public override object ParseValue(object value)
9 | {
10 | if (value is Id id) return id;
11 | var parsed = base.ParseValue(value);
12 | return parsed == null ? (Id?)null : new Id(parsed.ToString());
13 | }
14 |
15 | public override object ParseLiteral(IValue value)
16 | {
17 | var parsed = base.ParseLiteral(value);
18 | return parsed == null ? (Id?)null : new Id(parsed.ToString());
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/Types/JsonGraphType.cs:
--------------------------------------------------------------------------------
1 | using GraphQL.Types;
2 |
3 | namespace Our.Umbraco.GraphQL.Adapters.Types
4 | {
5 | public class JsonGraphType : StringGraphType
6 | {
7 | public JsonGraphType()
8 | {
9 | Name = "JSON";
10 | Description = "The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf).";
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/Types/LinkGraphType.cs:
--------------------------------------------------------------------------------
1 | using GraphQL.Types;
2 | using Umbraco.Cms.Core.Models;
3 |
4 | namespace Our.Umbraco.GraphQL.Adapters.Types
5 | {
6 | public class LinkGraphType : ObjectGraphType
7 | {
8 | public LinkGraphType()
9 | {
10 | Name = "Link";
11 |
12 | Field>("name");
13 | Field("target");
14 | Field>("type");
15 | Field>("url");
16 | Field("udi");
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/Types/LinkTypeGraphType.cs:
--------------------------------------------------------------------------------
1 | using GraphQL.Types;
2 | using Umbraco.Cms.Core.Models;
3 |
4 | namespace Our.Umbraco.GraphQL.Adapters.Types
5 | {
6 | public class LinkTypeGraphType : EnumerationGraphType
7 | {
8 | public LinkTypeGraphType()
9 | {
10 | Name = "LinkType";
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/Types/OrderByGraphType.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Reflection;
3 | using GraphQL;
4 | using GraphQL.Types;
5 | using Our.Umbraco.GraphQL.Types;
6 |
7 | namespace Our.Umbraco.GraphQL.Adapters.Types
8 | {
9 | public class OrderByGraphType : EnumerationGraphType
10 | {
11 | public OrderByGraphType(IComplexGraphType graphType)
12 | {
13 | if (graphType == null) throw new ArgumentNullException(nameof(graphType));
14 |
15 | Name = $"{graphType.Name}Order";
16 |
17 | foreach (var field in graphType.Fields)
18 | {
19 | Type fieldType = null;
20 | if (field.Type != null)
21 | {
22 | fieldType = field.Type;
23 | if (fieldType.IsGenericType && fieldType.GetGenericTypeDefinition() == typeof(NonNullGraphType<>))
24 | fieldType = fieldType.GenericTypeArguments[0];
25 | }
26 |
27 | if (field.ResolvedType != null)
28 | {
29 | fieldType = field.ResolvedType is NonNullGraphType nonNullGraphType
30 | ? nonNullGraphType.ResolvedType.GetType()
31 | : field.ResolvedType.GetType();
32 | }
33 |
34 | if (fieldType == null || typeof(ScalarGraphType).IsAssignableFrom(fieldType) == false) continue;
35 |
36 | var name = field.GetMetadata(nameof(MethodInfo))?.Name ?? field.Name;
37 |
38 | AddValue($"{field.Name}_ASC", $"Order by {field.Name} ascending.",
39 | new OrderBy(name, SortOrder.Ascending, field.Resolver.Resolve));
40 | AddValue($"{field.Name}_DESC", $"Order by {field.Name} descending.",
41 | new OrderBy(name, SortOrder.Descending, field.Resolver.Resolve));
42 | }
43 | }
44 | }
45 |
46 | public class OrderByGraphType : OrderByGraphType where TNodeType : IComplexGraphType
47 | {
48 | public OrderByGraphType() : base((IComplexGraphType) typeof(TNodeType).BuildNamedType())
49 | {
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/Types/Relay/ConnectionGraphType.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using GraphQL;
3 | using GraphQL.Types;
4 | using GraphQL.Types.Relay;
5 |
6 | namespace Our.Umbraco.GraphQL.Adapters.Types.Relay
7 | {
8 | public class ConnectionGraphType : ConnectionType where T : IGraphType
9 | {
10 | public ConnectionGraphType()
11 | {
12 | var text = typeof(T).GraphQLName();
13 |
14 | Name = text + "ConnectionGraph";
15 | Description = $"A connection from an object to a list of objects of type `{text}`.";
16 | }
17 | }
18 |
19 | public class ConnectionGraphType : ConnectionGraphType
20 | {
21 | public ConnectionGraphType(IGraphType graphType)
22 | {
23 | ResolvedType = graphType ?? throw new ArgumentNullException(nameof(graphType));
24 |
25 | Name = $"{graphType.Name}ConnectionGraph";
26 | Description = $"A connection from an object to a list of objects of type `{graphType.Name}`.";
27 |
28 | GetField("edges").ResolvedType = new ListGraphType(new EdgeGraphType(graphType));
29 | GetField("items").ResolvedType = new ListGraphType(graphType);
30 | }
31 |
32 | public IGraphType ResolvedType { get; }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/Types/Relay/EdgeGraphType.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using GraphQL.Types;
3 | using GraphQL.Types.Relay;
4 |
5 | namespace Our.Umbraco.GraphQL.Adapters.Types.Relay
6 | {
7 | public class EdgeGraphType : EdgeType where T : IGraphType
8 | {
9 | }
10 |
11 | public class EdgeGraphType : EdgeGraphType
12 | {
13 | public EdgeGraphType(IGraphType graphType)
14 | {
15 | ResolvedType = graphType ?? throw new ArgumentNullException(nameof(graphType));
16 |
17 | Name = $"{graphType.Name}Edge";
18 | Description = $"An edge in a connection from an object to another object of type `{graphType.Name}`.";
19 |
20 | GetField("node").ResolvedType = graphType;
21 | }
22 |
23 | public IGraphType ResolvedType { get; }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/Types/Relay/PageInfoGraphType.cs:
--------------------------------------------------------------------------------
1 | using GraphQL.Types.Relay;
2 |
3 | namespace Our.Umbraco.GraphQL.Adapters.Types.Relay
4 | {
5 | public class PageInfoGraphType : PageInfoType
6 | {
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/Types/Resolution/ITypeRegistry.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Reflection;
3 | using GraphQL.Types;
4 |
5 | namespace Our.Umbraco.GraphQL.Adapters.Types.Resolution
6 | {
7 | public interface ITypeRegistry
8 | {
9 | void Add() where TGraphType : IGraphType;
10 | TypeInfo Get(TypeInfo type);
11 | void Extend();
12 | IEnumerable GetExtending(TypeInfo type);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/Types/Resolution/TypeRegistry.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 | using GraphQL;
6 | using GraphQL.Types;
7 | using Microsoft.AspNetCore.Html;
8 | using Our.Umbraco.GraphQL.Adapters.PublishedContent.Types;
9 | using Our.Umbraco.GraphQL.Adapters.Types.Relay;
10 | using Our.Umbraco.GraphQL.Reflection;
11 | using Our.Umbraco.GraphQL.Types;
12 | using Our.Umbraco.GraphQL.Types.Relay;
13 | using Umbraco.Cms.Core.Models.Blocks;
14 | using Umbraco.Cms.Core.Strings;
15 |
16 | namespace Our.Umbraco.GraphQL.Adapters.Types.Resolution
17 | {
18 | public class TypeRegistry : ITypeRegistry
19 | {
20 | private readonly Dictionary _types = new Dictionary();
21 | private readonly Dictionary> _extends = new Dictionary>();
22 |
23 | public TypeRegistry()
24 | {
25 | Add();
26 | Add();
27 | Add();
28 | Add();
29 | Add();
30 | Add();
31 | Add();
32 | Add();
33 | Add();
34 | Add();
35 | Add();
36 | Add();
37 | Add();
38 | Add();
39 | Add();
40 | Add();
41 | Add();
42 | Add();
43 | Add();
44 | Add();
45 | Add();
46 | Add();
47 | }
48 |
49 | public void Add() where TGraphType : IGraphType =>
50 | _types[typeof(TType).GetTypeInfo()] = typeof(TGraphType).GetTypeInfo();
51 |
52 | public TypeInfo Get(TypeInfo type)
53 | {
54 | if (type.IsNullable())
55 | type = type.GenericTypeArguments[0].GetTypeInfo();
56 |
57 | return _types.TryGetValue(type, out var graphType) ? graphType : null;
58 | }
59 |
60 | public void Extend()
61 | {
62 | var extend = typeof(TExtend).GetTypeInfo();
63 | var with = typeof(TWith).GetTypeInfo();
64 |
65 | if (_extends.TryGetValue(extend, out var list) == false)
66 | {
67 | list = new List();
68 | _extends.Add(extend, list);
69 | }
70 |
71 | list.Add(with);
72 | }
73 |
74 | public IEnumerable GetExtending(TypeInfo type) =>
75 | _extends.TryGetValue(type, out var list)
76 | ? list.AsReadOnly()
77 | : Enumerable.Empty();
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/Types/UdiGraphType.cs:
--------------------------------------------------------------------------------
1 | using GraphQL.Language.AST;
2 | using GraphQL.Types;
3 | using Umbraco.Cms.Core;
4 |
5 | namespace Our.Umbraco.GraphQL.Adapters.Types
6 | {
7 | public class UdiGraphType : ScalarGraphType
8 | {
9 | public UdiGraphType()
10 | {
11 | Name = "UDI";
12 | Description = "Represents an entity identifier.";
13 | }
14 |
15 | public override object ParseLiteral(IValue value) => value is StringValue stringValue ? ParseValue(stringValue.Value) : null;
16 | public override object ParseValue(object value) => value is Udi udi ? udi : (UdiParser.TryParse(value?.ToString(), out udi) ? udi : default);
17 | public override object Serialize(object value) => value is Udi udi ? udi.ToString() : null;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/Visitors/CompositeGraphVisitor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using GraphQL.Types;
3 |
4 | namespace Our.Umbraco.GraphQL.Adapters.Visitors
5 | {
6 | public class CompositeGraphVisitor : GraphVisitor
7 | {
8 | private readonly IGraphVisitor[] _visitors;
9 |
10 | public CompositeGraphVisitor(params IGraphVisitor[] visitors)
11 | {
12 | _visitors = visitors ?? throw new ArgumentNullException(nameof(visitors));
13 | }
14 |
15 | public override void Visit(EnumerationGraphType graphType)
16 | {
17 | foreach (var visitor in _visitors) visitor.Visit(graphType);
18 | }
19 |
20 | public override void Visit(IInputObjectGraphType graphType)
21 | {
22 |
23 | foreach (var visitor in _visitors) visitor.Visit(graphType);
24 | }
25 |
26 | public override void Visit(IInterfaceGraphType graphType)
27 | {
28 | foreach (var visitor in _visitors) visitor.Visit(graphType);
29 | }
30 |
31 | public override void Visit(IObjectGraphType graphType)
32 | {
33 | foreach (var visitor in _visitors) visitor.Visit(graphType);
34 | }
35 |
36 | public override void Visit(ISchema schema)
37 | {
38 | foreach (var visitor in _visitors) visitor.Visit(schema);
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/Visitors/GraphVisitor.cs:
--------------------------------------------------------------------------------
1 | using GraphQL.Types;
2 |
3 | namespace Our.Umbraco.GraphQL.Adapters.Visitors
4 | {
5 | public abstract class GraphVisitor : IGraphVisitor
6 | {
7 | public virtual void Visit(EnumerationGraphType graphType)
8 | {
9 | }
10 |
11 | public virtual void Visit(IInputObjectGraphType graphType)
12 | {
13 | }
14 |
15 | public virtual void Visit(IInterfaceGraphType graphType)
16 | {
17 | }
18 |
19 | public virtual void Visit(IObjectGraphType graphType)
20 | {
21 | }
22 |
23 | public virtual void Visit(ISchema schema)
24 | {
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Adapters/Visitors/IGraphVisitor.cs:
--------------------------------------------------------------------------------
1 | using GraphQL.Types;
2 |
3 | namespace Our.Umbraco.GraphQL.Adapters.Visitors
4 | {
5 | public interface IGraphVisitor
6 | {
7 | void Visit(EnumerationGraphType graphType);
8 | void Visit(IInputObjectGraphType graphType);
9 | void Visit(IInterfaceGraphType graphType);
10 | void Visit(IObjectGraphType graphType);
11 | void Visit(ISchema schema);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Attributes/DefaultValueAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Our.Umbraco.GraphQL.Attributes
4 | {
5 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Parameter |
6 | AttributeTargets.Property)]
7 | public class DefaultValueAttribute : Attribute
8 | {
9 | public DefaultValueAttribute(object defaultValue)
10 | {
11 | DefaultValue = defaultValue;
12 | }
13 |
14 | public object DefaultValue { get; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Attributes/DeprecatedAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Our.Umbraco.GraphQL.Attributes
4 | {
5 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Enum | AttributeTargets.Field |
6 | AttributeTargets.Interface | AttributeTargets.Method | AttributeTargets.Property |
7 | AttributeTargets.Struct)]
8 | public class DeprecatedAttribute : Attribute
9 | {
10 | public DeprecatedAttribute(string deprecationReason)
11 | {
12 | DeprecationReason = deprecationReason;
13 | }
14 |
15 | public string DeprecationReason { get; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Attributes/DescriptionAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Our.Umbraco.GraphQL.Attributes
4 | {
5 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Enum | AttributeTargets.Field |
6 | AttributeTargets.Interface | AttributeTargets.Method | AttributeTargets.Parameter |
7 | AttributeTargets.Property | AttributeTargets.Struct)]
8 | public class DescriptionAttribute : Attribute
9 | {
10 | public DescriptionAttribute(string description)
11 | {
12 | Description = description;
13 | }
14 |
15 | public string Description { get; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Attributes/IgnoreAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Our.Umbraco.GraphQL.Attributes
4 | {
5 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Property)]
6 | public class IgnoreAttribute : Attribute
7 | {
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Attributes/InjectAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Our.Umbraco.GraphQL.Attributes
4 | {
5 | [AttributeUsage(AttributeTargets.Parameter)]
6 | public class InjectAttribute : Attribute
7 | {
8 |
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Attributes/NameAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Our.Umbraco.GraphQL.Attributes
4 | {
5 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Enum | AttributeTargets.Field |
6 | AttributeTargets.Interface | AttributeTargets.Method | AttributeTargets.Parameter |
7 | AttributeTargets.Property | AttributeTargets.Struct)]
8 | public class NameAttribute : Attribute
9 | {
10 | public NameAttribute(string name)
11 | {
12 | Name = name ?? throw new ArgumentNullException(nameof(name));
13 | }
14 |
15 | public string Name { get; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Attributes/NonNullAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Our.Umbraco.GraphQL.Attributes
4 | {
5 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Parameter |
6 | AttributeTargets.Property)]
7 | public class NonNullAttribute : Attribute
8 | {
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Attributes/NonNullItemAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Our.Umbraco.GraphQL.Attributes
4 | {
5 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Parameter |
6 | AttributeTargets.Property)]
7 | public class NonNullItemAttribute : Attribute
8 | {
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Builders/BuiltSchema.cs:
--------------------------------------------------------------------------------
1 | using GraphQL;
2 | using GraphQL.Conversion;
3 | using GraphQL.Instrumentation;
4 | using GraphQL.Introspection;
5 | using GraphQL.Types;
6 | using GraphQL.Utilities;
7 | using Our.Umbraco.GraphQL.Types;
8 | using System;
9 | using System.Collections.Generic;
10 | using System.Reflection;
11 |
12 | namespace Our.Umbraco.GraphQL.Builders
13 | {
14 | public class BuiltSchema : ISchema
15 | {
16 | private readonly ISchemaBuilder _builder;
17 | private Lazy _schema;
18 |
19 | public BuiltSchema(ISchemaBuilder builder)
20 | {
21 | _builder = builder;
22 | _schema = new Lazy(BuildSchema);
23 | }
24 |
25 | public ExperimentalFeatures Features { get => _schema.Value.Features; set => _schema.Value.Features = value; }
26 | public bool Initialized => _schema.Value.Initialized;
27 | public INameConverter NameConverter => _schema.Value.NameConverter;
28 | public IFieldMiddlewareBuilder FieldMiddleware => _schema.Value.FieldMiddleware;
29 | public IObjectGraphType Query { get => _schema.Value.Query; set => _schema.Value.Query = value; }
30 | public IObjectGraphType Mutation { get => _schema.Value.Mutation; set => _schema.Value.Mutation = value; }
31 | public IObjectGraphType Subscription { get => _schema.Value.Subscription; set => _schema.Value.Subscription = value; }
32 | public SchemaDirectives Directives => _schema.Value.Directives;
33 | public SchemaTypes AllTypes => _schema.Value.AllTypes;
34 | public IEnumerable AdditionalTypes => _schema.Value.AdditionalTypes;
35 | public IEnumerable AdditionalTypeInstances => _schema.Value.AdditionalTypeInstances;
36 | public IEnumerable<(Type clrType, Type graphType)> TypeMappings => _schema.Value.TypeMappings;
37 | public IEnumerable<(Type clrType, Type graphType)> BuiltInTypeMappings => _schema.Value.BuiltInTypeMappings;
38 | public ISchemaFilter Filter { get => _schema.Value.Filter; set => _schema.Value.Filter = value; }
39 | public ISchemaComparer Comparer { get => _schema.Value.Comparer; set => _schema.Value.Comparer = value; }
40 | public FieldType SchemaMetaFieldType => _schema.Value.SchemaMetaFieldType;
41 | public FieldType TypeMetaFieldType => _schema.Value.TypeMetaFieldType;
42 | public FieldType TypeNameMetaFieldType => _schema.Value.TypeNameMetaFieldType;
43 | public Dictionary Metadata => _schema.Value.Metadata;
44 | public string Description { get => _schema.Value.Description; set => _schema.Value.Description = value; }
45 |
46 | public TType GetMetadata(string key, TType defaultValue = default) => _schema.Value.GetMetadata(key, defaultValue);
47 | public TType GetMetadata(string key, Func defaultValueFactory) => _schema.Value.GetMetadata(key, defaultValueFactory);
48 | public bool HasMetadata(string key) => _schema.Value.HasMetadata(key);
49 | public void Initialize() => _schema.Value.Initialize();
50 | public void RegisterType(IGraphType type) => _schema.Value.RegisterType(type);
51 | public void RegisterType(Type type) => _schema.Value.RegisterType(type);
52 | public void RegisterTypeMapping(Type clrType, Type graphType) => _schema.Value.RegisterTypeMapping(clrType, graphType);
53 | public void RegisterVisitor(ISchemaNodeVisitor visitor) => _schema.Value.RegisterVisitor(visitor);
54 | public void RegisterVisitor(Type type) => _schema.Value.RegisterVisitor(type);
55 |
56 | public void InvalidateSchema()
57 | {
58 | if (!_schema.IsValueCreated) return;
59 | _schema = new Lazy(BuildSchema);
60 | }
61 |
62 | private ISchema BuildSchema() => _builder.Build();
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Builders/ISchemaBuilder.cs:
--------------------------------------------------------------------------------
1 | using GraphQL.Types;
2 | using System;
3 |
4 | namespace Our.Umbraco.GraphQL.Builders
5 | {
6 | public interface ISchemaBuilder
7 | {
8 | ISchema Build();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Builders/SchemaBuilder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Reflection;
3 | using GraphQL.Types;
4 | using Our.Umbraco.GraphQL.Adapters;
5 | using Our.Umbraco.GraphQL.Adapters.Visitors;
6 | using Our.Umbraco.GraphQL.Types;
7 |
8 | namespace Our.Umbraco.GraphQL.Builders
9 | {
10 | public class SchemaBuilder : ISchemaBuilder
11 | {
12 | private readonly IGraphTypeAdapter _graphTypeAdapter;
13 | private readonly IGraphVisitor _visitor;
14 | private readonly IServiceProvider _serviceProvider;
15 |
16 | public SchemaBuilder(IGraphTypeAdapter graphTypeAdapter, IServiceProvider serviceProvider, IGraphVisitor visitor)
17 | {
18 | _graphTypeAdapter = graphTypeAdapter ?? throw new ArgumentNullException(nameof(graphTypeAdapter));
19 | _serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
20 | _visitor = visitor;
21 | }
22 |
23 | public virtual Type SchemaType => typeof(Schema);
24 |
25 | public virtual ISchema Build()
26 | {
27 | var schema = new Schema(_serviceProvider);
28 |
29 | AddProperties(schema);
30 | _visitor?.Visit(schema);
31 |
32 | return schema;
33 | }
34 |
35 | protected virtual void AddProperties(Schema schema)
36 | {
37 | schema.Query = GenerateFromProperty("Query", true);
38 | }
39 |
40 | protected virtual IObjectGraphType GenerateFromProperty(string propertyName, bool throwError)
41 | {
42 | var queryPropertyInfo = SchemaType.GetProperty(propertyName);
43 | if (queryPropertyInfo == null)
44 | {
45 | if (throwError) throw new ArgumentException($"Could not find property '{propertyName}' on {SchemaType.FullName}.");
46 | return null;
47 | }
48 |
49 | if (queryPropertyInfo.CanRead == false)
50 | {
51 | if (throwError) throw new ArgumentException($"Could not find getter for '{propertyName}' on {SchemaType.FullName}.");
52 | return null;
53 | }
54 |
55 | return (IObjectGraphType)_graphTypeAdapter.Adapt(queryPropertyInfo.GetMethod.ReturnType.GetTypeInfo());
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Compose/GraphQLComponent.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Examine;
3 | using Newtonsoft.Json.Linq;
4 | using Our.Umbraco.GraphQL.Adapters.Examine.Types;
5 | using Our.Umbraco.GraphQL.Adapters.PublishedContent.Types;
6 | using Our.Umbraco.GraphQL.Adapters.Types;
7 | using Our.Umbraco.GraphQL.Adapters.Types.Resolution;
8 | using Our.Umbraco.GraphQL.Types;
9 | using Our.Umbraco.GraphQL.Types.PublishedContent;
10 | using Umbraco.Cms.Core;
11 | using Umbraco.Cms.Core.Composing;
12 | using Umbraco.Cms.Core.Models.PublishedContent;
13 | using Umbraco.Cms.Core.Models;
14 |
15 | namespace Our.Umbraco.GraphQL.Compose
16 | {
17 | public class GraphQLComponent : IComponent
18 | {
19 | private readonly ITypeRegistry _typeRegistry;
20 |
21 | public GraphQLComponent(ITypeRegistry typeRegistry)
22 | {
23 | _typeRegistry = typeRegistry ?? throw new ArgumentNullException(nameof(typeRegistry));
24 | }
25 |
26 | public void Initialize()
27 | {
28 | _typeRegistry.Add();
29 | _typeRegistry.Add();
30 | _typeRegistry.Add();
31 | _typeRegistry.Add();
32 | _typeRegistry.Add();
33 | _typeRegistry.Add();
34 | _typeRegistry.Add ();
35 | _typeRegistry.Add();
36 | _typeRegistry.Add();
37 | _typeRegistry.Add();
38 | _typeRegistry.Add();
39 |
40 | _typeRegistry.Extend();
41 | _typeRegistry.Extend();
42 | _typeRegistry.Extend();
43 | }
44 |
45 | public void Terminate()
46 | {
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Compose/GraphQLPipelineFilter.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Builder;
2 | using Our.Umbraco.GraphQL.Web;
3 | using Our.Umbraco.GraphQL.Web.Middleware;
4 | using Umbraco.Cms.Web.Common.ApplicationBuilder;
5 |
6 | namespace Our.Umbraco.GraphQL.Compose
7 | {
8 | public class GraphQLPipelineFilter : UmbracoPipelineFilter
9 | {
10 | public GraphQLPipelineFilter(GraphQLServerOptions options) : base(nameof(GraphQLPipelineFilter))
11 | {
12 | PostPipeline = a =>
13 | {
14 | if (options.EnableCors && !string.IsNullOrWhiteSpace(options.CorsPolicyName))
15 | {
16 | a.UseCors(options.CorsPolicyName);
17 | }
18 | a.UseMiddleware();
19 | };
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Compose/GraphQLUmbracoOptionsSetup.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Options;
2 | using Our.Umbraco.GraphQL.Web;
3 | using Umbraco.Cms.Web.Common.ApplicationBuilder;
4 |
5 | namespace Our.Umbraco.GraphQL.Compose
6 | {
7 | public class GraphQLUmbracoOptionsSetup : IConfigureOptions
8 | {
9 | private readonly IOptions _options;
10 |
11 | public GraphQLUmbracoOptionsSetup(IOptions options)
12 | {
13 | _options = options;
14 | }
15 |
16 | public void Configure(UmbracoPipelineOptions options)
17 | {
18 | options.AddFilter(new GraphQLPipelineFilter(_options.Value));
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Composing/CompositionExtensions.cs:
--------------------------------------------------------------------------------
1 | using Umbraco.Cms.Core.DependencyInjection;
2 |
3 | namespace Our.Umbraco.GraphQL.Composing
4 | {
5 | public static class CompositionExtensions
6 | {
7 | public static GraphVisitorCollectionBuilder GraphVisitors(this IUmbracoBuilder builder) =>
8 | builder.WithCollectionBuilder();
9 |
10 | public static FieldMiddlewareCollectionBuilder FieldMiddlewares(this IUmbracoBuilder builder) =>
11 | builder.WithCollectionBuilder();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Composing/FieldMiddlewareCollection.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Our.Umbraco.GraphQL.Middleware;
4 | using Umbraco.Cms.Core.Composing;
5 |
6 | namespace Our.Umbraco.GraphQL.Composing
7 | {
8 | public class FieldMiddlewareCollection : BuilderCollectionBase
9 | {
10 | public FieldMiddlewareCollection(Func> items)
11 | : base(items)
12 | {
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Composing/FieldMiddlewareCollectionBuilder.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 | using Our.Umbraco.GraphQL.Middleware;
3 | using Umbraco.Cms.Core.Composing;
4 |
5 | namespace Our.Umbraco.GraphQL.Composing
6 | {
7 | public class FieldMiddlewareCollectionBuilder : OrderedCollectionBuilderBase
8 | {
9 | protected override ServiceLifetime CollectionLifetime => ServiceLifetime.Scoped;
10 |
11 | protected override FieldMiddlewareCollectionBuilder This => this;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Composing/GraphVisitorCollection.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Our.Umbraco.GraphQL.Adapters.Visitors;
4 | using Umbraco.Cms.Core.Composing;
5 |
6 | namespace Our.Umbraco.GraphQL.Composing
7 | {
8 | public class GraphVisitorCollection : BuilderCollectionBase
9 | {
10 | public GraphVisitorCollection(Func> items)
11 | : base(items)
12 | {
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Composing/GraphVisitorCollectionBuilder.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.DependencyInjection;
2 | using Our.Umbraco.GraphQL.Adapters.Visitors;
3 | using Umbraco.Cms.Core.Composing;
4 |
5 | namespace Our.Umbraco.GraphQL.Composing
6 | {
7 | public class GraphVisitorCollectionBuilder : OrderedCollectionBuilderBase
8 | {
9 | public GraphVisitorCollectionBuilder()
10 | {
11 | }
12 |
13 | protected override ServiceLifetime CollectionLifetime => ServiceLifetime.Singleton;
14 |
15 | protected override GraphVisitorCollectionBuilder This => this;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Constants.cs:
--------------------------------------------------------------------------------
1 | namespace Our.Umbraco.GraphQL
2 | {
3 | public class Constants
4 | {
5 | public const string ProductName = "Our.Umbraco.GraphQL";
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/FieldMiddleware/IFieldMiddleware.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using GraphQL;
3 | using GraphQL.Instrumentation;
4 |
5 | namespace Our.Umbraco.GraphQL.Middleware
6 | {
7 | public interface IFieldMiddleware
8 | {
9 | Task Resolve(ResolveFieldContext context, FieldMiddlewareDelegate next);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Filters/AndFilter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 |
5 | namespace Our.Umbraco.GraphQL.Filters
6 | {
7 | public class AndFilter : IFilter
8 | {
9 | private readonly IEnumerable _subFilters;
10 |
11 | public AndFilter(IEnumerable subFilters)
12 | {
13 | _subFilters = subFilters ?? throw new ArgumentNullException(nameof(subFilters));
14 | }
15 |
16 | public bool IsSatisfiedBy(object input)
17 | {
18 | foreach (var filter in _subFilters)
19 | {
20 | if (false == filter.IsSatisfiedBy(input)) return false;
21 | }
22 |
23 | return true;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Filters/ContainsFilter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Our.Umbraco.GraphQL.Filters
4 | {
5 | public class ContainsFilter : IFilter
6 | {
7 | private readonly string _value;
8 | private readonly Func _valueResolver;
9 |
10 | public ContainsFilter(Func valueResolver, object value)
11 | {
12 | _valueResolver = valueResolver ?? throw new ArgumentNullException(nameof(valueResolver));
13 | _value = Convert.ToString(value);
14 | }
15 |
16 | public bool IsSatisfiedBy(object input)
17 | {
18 | var value = _valueResolver(input);
19 | if (value == null || _value == null)
20 | {
21 | return false;
22 | }
23 | return Convert.ToString(value).IndexOf(_value, StringComparison.InvariantCultureIgnoreCase) > -1;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Filters/EndsWithFilter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Our.Umbraco.GraphQL.Filters
4 | {
5 | public class EndsWithFilter : IFilter
6 | {
7 | private readonly string _value;
8 | private readonly Func _valueResolver;
9 |
10 | public EndsWithFilter(Func valueResolver, object value)
11 | {
12 | _valueResolver = valueResolver ?? throw new ArgumentNullException(nameof(valueResolver));
13 | _value = Convert.ToString(value);
14 | }
15 |
16 | public bool IsSatisfiedBy(object input)
17 | {
18 | var value = _valueResolver(input);
19 | if (value == null || _value == null)
20 | {
21 | return false;
22 | }
23 | return Convert.ToString(value).EndsWith(_value, StringComparison.InvariantCultureIgnoreCase);
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Filters/EqFilter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Our.Umbraco.GraphQL.Filters
4 | {
5 | public class EqFilter : IFilter
6 | {
7 | private readonly object _value;
8 | private readonly Func _valueResolver;
9 |
10 | public EqFilter(Func valueResolver, object value)
11 | {
12 | _valueResolver = valueResolver ?? throw new ArgumentNullException(nameof(valueResolver));
13 | _value = value;
14 | }
15 |
16 | public bool IsSatisfiedBy(object input)
17 | {
18 | var value = _valueResolver(input);
19 | return Equals(value, _value);
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Filters/GtFilter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 |
4 | namespace Our.Umbraco.GraphQL.Filters
5 | {
6 | public class GtFilter : IFilter
7 | {
8 | private readonly object _value;
9 | private readonly Func _valueResolver;
10 |
11 | public GtFilter(Func valueResolver, object value)
12 | {
13 | _valueResolver = valueResolver ?? throw new ArgumentNullException(nameof(valueResolver));
14 | _value = value;
15 | }
16 |
17 | public bool IsSatisfiedBy(object input)
18 | {
19 | var value = _valueResolver(input);
20 | return Comparer.DefaultInvariant.Compare(value, _value) > 0;
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Filters/GteFilter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 |
4 | namespace Our.Umbraco.GraphQL.Filters
5 | {
6 | public class GteFilter : IFilter
7 | {
8 | private readonly object _value;
9 | private readonly Func _valueResolver;
10 |
11 | public GteFilter(Func valueResolver, object value)
12 | {
13 | _valueResolver = valueResolver ?? throw new ArgumentNullException(nameof(valueResolver));
14 | _value = value;
15 | }
16 |
17 | public bool IsSatisfiedBy(object input)
18 | {
19 | var value = _valueResolver(input);
20 | return Comparer.DefaultInvariant.Compare(value, _value) >= 0;
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Filters/IFilter.cs:
--------------------------------------------------------------------------------
1 | namespace Our.Umbraco.GraphQL.Filters
2 | {
3 | public interface IFilter
4 | {
5 | bool IsSatisfiedBy(object input);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Filters/InFilter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Our.Umbraco.GraphQL.Filters
4 | {
5 | public class InFilter : IFilter
6 | {
7 | private readonly object[] _value;
8 | private readonly Func _valueResolver;
9 |
10 | public InFilter(Func valueResolver, object value)
11 | {
12 | _valueResolver = valueResolver ?? throw new ArgumentNullException(nameof(valueResolver));
13 | _value = (object[]) value;
14 | }
15 |
16 | public bool IsSatisfiedBy(object input)
17 | {
18 | var value = _valueResolver(input);
19 | return Array.Exists(_value, x => Equals(x, value));
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Filters/LtFilter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 |
4 | namespace Our.Umbraco.GraphQL.Filters
5 | {
6 | public class LtFilter : IFilter
7 | {
8 | private readonly object _value;
9 | private readonly Func _valueResolver;
10 |
11 | public LtFilter(Func valueResolver, object value)
12 | {
13 | _valueResolver = valueResolver ?? throw new ArgumentNullException(nameof(valueResolver));
14 | _value = value;
15 | }
16 |
17 | public bool IsSatisfiedBy(object input)
18 | {
19 | var value = _valueResolver(input);
20 | return Comparer.DefaultInvariant.Compare(value, _value) < 0;
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Filters/LteFilter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 |
4 | namespace Our.Umbraco.GraphQL.Filters
5 | {
6 | public class LteFilter : IFilter
7 | {
8 | private readonly object _value;
9 | private readonly Func _valueResolver;
10 |
11 | public LteFilter(Func valueResolver, object value)
12 | {
13 | _valueResolver = valueResolver ?? throw new ArgumentNullException(nameof(valueResolver));
14 | _value = value;
15 | }
16 |
17 | public bool IsSatisfiedBy(object input)
18 | {
19 | var value = _valueResolver(input);
20 | return Comparer.DefaultInvariant.Compare(value, _value) <= 0;
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Filters/NotFilter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Our.Umbraco.GraphQL.Filters
4 | {
5 | public class NotFilter : IFilter
6 | {
7 | private readonly IFilter _filter;
8 |
9 | public NotFilter(IFilter filter)
10 | {
11 | _filter = filter ?? throw new ArgumentNullException(nameof(filter));
12 | }
13 |
14 | public bool IsSatisfiedBy(object input)
15 | {
16 | return false == _filter.IsSatisfiedBy(input);
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Filters/OrFilter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 |
5 | namespace Our.Umbraco.GraphQL.Filters
6 | {
7 | public class OrFilter : IFilter
8 | {
9 | private readonly IEnumerable _subFilters;
10 |
11 | public OrFilter(IEnumerable subFilters)
12 | {
13 | _subFilters = subFilters ?? throw new ArgumentNullException(nameof(subFilters));
14 | }
15 |
16 | public bool IsSatisfiedBy(object input)
17 | {
18 | foreach (var filter in _subFilters)
19 | {
20 | if (filter.IsSatisfiedBy(input)) return true;
21 | }
22 |
23 | return false;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Filters/StartsWithFilter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Our.Umbraco.GraphQL.Filters
4 | {
5 | public class StartsWithFilter : IFilter
6 | {
7 | private readonly string _value;
8 | private readonly Func _valueResolver;
9 |
10 | public StartsWithFilter(Func valueResolver, object value)
11 | {
12 | _valueResolver = valueResolver ?? throw new ArgumentNullException(nameof(valueResolver));
13 | _value = Convert.ToString(value);
14 | }
15 |
16 | public bool IsSatisfiedBy(object input)
17 | {
18 | var value = _valueResolver(input);
19 | if (value == null || _value == null)
20 | {
21 | return false;
22 | }
23 | return Convert.ToString(value).StartsWith(_value, StringComparison.InvariantCultureIgnoreCase);
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/IUserContext.cs:
--------------------------------------------------------------------------------
1 | using Umbraco.Cms.Web.Common.UmbracoContext;
2 |
3 | namespace Our.Umbraco.GraphQL
4 | {
5 | public interface IUserContext
6 | {
7 | UmbracoContext UmbracoContext { get; }
8 | }
9 |
10 | internal class UserContext
11 | {
12 | public UserContext(UmbracoContext umbracoContext)
13 | {
14 | UmbracoContext = umbracoContext ?? throw new System.ArgumentNullException(nameof(umbracoContext));
15 | }
16 |
17 | public UmbracoContext UmbracoContext { get; }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Json/Converters/InputsConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using GraphQL;
4 | using Newtonsoft.Json;
5 |
6 | namespace Our.Umbraco.GraphQL.Json.Converters
7 | {
8 | internal class InputsConverter : JsonConverter
9 | {
10 | public override bool CanConvert(Type objectType) => objectType == typeof(Inputs);
11 |
12 | public override bool CanWrite => false;
13 |
14 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
15 | JsonSerializer serializer)
16 | {
17 | var dict = serializer.Deserialize>(reader);
18 | return new Inputs(dict ?? new Dictionary());
19 | }
20 |
21 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) =>
22 | throw new NotSupportedException();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Our.Umbraco.GraphQL.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | GraphQL for Umbraco
4 | Umbraco Community
5 | umbraco-community
6 | A GraphQL server for Umbraco
7 | LICENSE
8 | https://github.com/umbraco-community/umbraco-graphql
9 | umbraco umbracocms graphql
10 | Copyright © 2023 Rasmus John Pedersen, Andrew McKaskill
11 | false
12 | 11.0.0-alpha001
13 |
14 |
15 |
16 | net7.0
17 | Our.Umbraco.GraphQL
18 | Our.Umbraco.GraphQL
19 | Web\UI\
20 | $(DefaultItemExcludes);$(UIRoot)node_modules\**;$(UIRoot).sass-cache\**
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 |
3 | [assembly: InternalsVisibleTo("Our.Umbraco.GraphQL.Tests")]
4 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Reflection/TypeInfoExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 | using System.Threading.Tasks;
6 | using GraphQL.Types;
7 |
8 | namespace Our.Umbraco.GraphQL.Reflection
9 | {
10 | internal static class TypeInfoExtensions
11 | {
12 | public static bool IsNullable(this TypeInfo type) => type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
13 |
14 | public static TypeInfo GetReturnType(this MemberInfo memberInfo)
15 | {
16 | switch (memberInfo)
17 | {
18 | case FieldInfo fieldInfo:
19 | return fieldInfo.FieldType.GetTypeInfo();
20 | case MethodInfo methodInfo:
21 | return methodInfo.ReturnType.GetTypeInfo();
22 | case PropertyInfo propertyInfo:
23 | return propertyInfo.GetMethod.ReturnType.GetTypeInfo();
24 | default:
25 | throw new ArgumentOutOfRangeException(nameof(memberInfo));
26 | }
27 | }
28 |
29 | public static TypeInfo Unwrap(this TypeInfo typeInfo)
30 | {
31 | if (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(Task<>))
32 | typeInfo = typeInfo.GenericTypeArguments[0].GetTypeInfo();
33 |
34 | var isNullable = typeInfo.IsNullable();
35 | if (isNullable)
36 | return typeInfo.GenericTypeArguments[0].GetTypeInfo();
37 |
38 | var enumerableArgument = GetEnumerableArgument(typeInfo);
39 | return enumerableArgument != null ? enumerableArgument.GetTypeInfo() : typeInfo;
40 | }
41 |
42 | public static TypeInfo Wrap(this TypeInfo graphType, TypeInfo typeInfo, bool isNonNull, bool isNonNullItem)
43 | => Wrap(graphType, typeInfo, isNonNull, isNonNullItem, true, out _);
44 |
45 | public static TypeInfo Wrap(this TypeInfo graphType, TypeInfo typeInfo, bool isNonNull, bool isNonNullItem, bool checkEnumerable, out bool isEnumerable)
46 | {
47 | isEnumerable = false;
48 |
49 | if (graphType == null)
50 | return null;
51 |
52 | var enumerableArgument = checkEnumerable ? GetEnumerableArgument(typeInfo) : null;
53 | isEnumerable = enumerableArgument != null;
54 |
55 | if (typeInfo.IsValueType && typeInfo.IsNullable() == false || enumerableArgument != null &&
56 | (enumerableArgument.IsValueType && enumerableArgument.IsNullable() == false || isNonNullItem))
57 | graphType = typeof(NonNullGraphType<>).MakeGenericType(graphType).GetTypeInfo();
58 |
59 | if (isEnumerable)
60 | graphType = typeof(ListGraphType<>).MakeGenericType(graphType).GetTypeInfo();
61 |
62 | if (isNonNull && typeof(NonNullGraphType).IsAssignableFrom(graphType) == false)
63 | graphType = typeof(NonNullGraphType<>).MakeGenericType(graphType).GetTypeInfo();
64 |
65 | return graphType;
66 | }
67 |
68 | public static TypeInfo GetEnumerableArgument(this TypeInfo typeInfo)
69 | {
70 | if (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(Task<>))
71 | typeInfo = typeInfo.GenericTypeArguments[0].GetTypeInfo();
72 |
73 | if (typeInfo == typeof(string))
74 | return null;
75 |
76 | if (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(IEnumerable<>))
77 | return typeInfo.GenericTypeArguments[0].GetTypeInfo();
78 |
79 | var enumerableInterface = typeInfo.ImplementedInterfaces.FirstOrDefault(x =>
80 | x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IEnumerable<>));
81 |
82 | return enumerableInterface?.GenericTypeArguments[0].GetTypeInfo();
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Resources/playground.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | GraphQL Playground
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
48 |
49 |
50 | Loading
51 | GraphQL Playground
52 |
53 |
54 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Types/ConnectionExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using Our.Umbraco.GraphQL.Types.Relay;
6 |
7 | namespace Our.Umbraco.GraphQL.Types
8 | {
9 | public static class ConnectionExtensions
10 | {
11 | public static Connection ToConnection(this IEnumerable source, Func idSelector,
12 | int? first = null, string after = null, int? last = null, string before = null, long? totalCount = null)
13 | {
14 | if(first < 0)
15 | throw new ArgumentException($"{nameof(first)} cannot be less than 0.", nameof(first));
16 |
17 | if(last < 0)
18 | throw new ArgumentException($"{nameof(last)} cannot be less than 0.", nameof(last));
19 |
20 | var sourceList = source.ToList();
21 |
22 | var edges = sourceList.Select(x => new Edge
23 | {
24 | Cursor = IdToCursor(idSelector(x)),
25 | Node = x
26 | });
27 |
28 | if (after != null) edges = edges.SkipWhile(x => x.Cursor != after).Skip(1);
29 | if (before != null) edges = edges.TakeWhile(x => x.Cursor != before);
30 | if (first.HasValue) edges = edges.Take(first.Value);
31 | if (last.HasValue) edges = edges.Reverse().Take(last.Value).Reverse();
32 |
33 | var edgeList = edges.ToList();
34 | var endCursor = edgeList.LastOrDefault()?.Cursor;
35 | var startCursor = edgeList.FirstOrDefault()?.Cursor;
36 |
37 | var firstCursor = sourceList.Count > 0 ? IdToCursor(idSelector(sourceList.First())) : null;
38 | var lastCursor = sourceList.Count > 0 ? IdToCursor(idSelector(sourceList.Last())) : null;
39 |
40 | return new Connection
41 | {
42 | Edges = edgeList,
43 | TotalCount = totalCount,
44 | PageInfo = new PageInfo
45 | {
46 | EndCursor = endCursor,
47 | HasNextPage = endCursor != lastCursor,
48 | HasPreviousPage = startCursor != firstCursor,
49 | StartCursor = startCursor
50 | }
51 | };
52 | }
53 |
54 | private static string IdToCursor(object id) => IdToCursor(new Id(id.ToString()));
55 |
56 | private static string IdToCursor(Id id) => Convert.ToBase64String(Encoding.UTF8.GetBytes($"connection:{id}"));
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Types/Id.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel;
3 |
4 | namespace Our.Umbraco.GraphQL.Types
5 | {
6 | public struct Id
7 | {
8 | public Id(string value)
9 | {
10 | if (value == null) throw new ArgumentNullException(nameof(value));
11 | if (value == string.Empty)
12 | throw new ArgumentException($"{nameof(value)} cannot be empty.", nameof(value));
13 |
14 | Value = value;
15 | }
16 |
17 | public string Value { get; }
18 |
19 | public T As()
20 | {
21 | var converter = TypeDescriptor.GetConverter(typeof(T));
22 | if (converter.CanConvertFrom(typeof(string)))
23 | return (T)converter.ConvertFrom(Value);
24 |
25 | return (T)Convert.ChangeType(Value, typeof(T));
26 | }
27 |
28 | public bool Equals(Id other) => Value == other.Value;
29 |
30 | public override bool Equals(object obj) => obj is Id other && Equals(other);
31 |
32 | public override int GetHashCode() => Value.GetHashCode();
33 |
34 | public override string ToString() => Value;
35 |
36 | public static bool operator ==(Id left, Id right) => left.Equals(right);
37 |
38 | public static bool operator !=(Id left, Id right) => left.Equals(right) == false;
39 |
40 | public static implicit operator Id(string value) => new Id(value);
41 |
42 | public static implicit operator string(Id id) => id.Value;
43 |
44 | public static implicit operator Id?(string value) => string.IsNullOrEmpty(value) ? null : (Id?)new Id(value);
45 |
46 | public static implicit operator string(Id? id) => id?.Value;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Types/Mutation.cs:
--------------------------------------------------------------------------------
1 | namespace Our.Umbraco.GraphQL.Types
2 | {
3 | public class Mutation
4 | {
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Types/OrderBy.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using GraphQL;
3 |
4 | namespace Our.Umbraco.GraphQL.Types
5 | {
6 | public class OrderBy
7 | {
8 | private readonly Func _resolver;
9 |
10 | internal OrderBy(string field, SortOrder direction, Func resolver)
11 | {
12 | _resolver = resolver ?? throw new ArgumentNullException(nameof(resolver));
13 | Field = field ?? throw new ArgumentNullException(nameof(field));
14 | Direction = direction;
15 | }
16 |
17 | public string Field { get; }
18 | public SortOrder Direction { get; }
19 |
20 | public object Resolve(TSource source)
21 | {
22 | return _resolver(new ResolveFieldContext
23 | {
24 | Source = source,
25 | });
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Types/OrderByExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 |
4 | namespace Our.Umbraco.GraphQL.Types
5 | {
6 | public static class OrderByExtensions
7 | {
8 | public static IEnumerable OrderBy(this IEnumerable source, IEnumerable orderBy)
9 | {
10 | if (orderBy == null) return source;
11 |
12 | foreach (var order in orderBy)
13 | {
14 | if (source is IOrderedEnumerable ordered)
15 | {
16 | source = order.Direction == SortOrder.Ascending
17 | ? ordered.ThenBy(order.Resolve)
18 | : ordered.ThenByDescending(order.Resolve);
19 | }
20 | else
21 | {
22 | source = order.Direction == SortOrder.Ascending
23 | ? source.OrderBy(order.Resolve)
24 | : source.OrderByDescending(order.Resolve);
25 | }
26 | }
27 |
28 | return source;
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Types/PublishedContent/PublishedContentAtRootQuery.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using Our.Umbraco.GraphQL.Attributes;
5 | using Our.Umbraco.GraphQL.Types.Relay;
6 | using Umbraco.Cms.Core.Models.PublishedContent;
7 | using Umbraco.Cms.Core.PublishedCache;
8 |
9 | namespace Our.Umbraco.GraphQL.Types.PublishedContent
10 | {
11 | public class PublishedContentAtRootQuery
12 | {
13 | private readonly IPublishedSnapshotAccessor _snapshotAccessor;
14 |
15 | public PublishedContentAtRootQuery(IPublishedSnapshotAccessor snapshotAccessor)
16 | {
17 | _snapshotAccessor = snapshotAccessor ?? throw new ArgumentNullException(nameof(snapshotAccessor));
18 | }
19 |
20 |
21 | [NonNull, NonNullItem]
22 | public Connection All(string culture = null, int? first = null, string after = null,
23 | int? last = null, string before = null, IEnumerable orderBy = null)
24 | {
25 | if (!_snapshotAccessor.TryGetPublishedSnapshot(out var publishedSnapshot))
26 | {
27 | throw new InvalidOperationException("Wasn't possible to a get a valid Snapshot");
28 | }
29 |
30 | var rootContent = publishedSnapshot.Content.GetAtRoot(culture).OrderBy(orderBy).ToList();
31 | return rootContent.ToConnection(x => x.Key, first, after, last, before, rootContent.Count);
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Types/PublishedContent/PublishedContentByTypeQuery.cs:
--------------------------------------------------------------------------------
1 | namespace Our.Umbraco.GraphQL.Types.PublishedContent
2 | {
3 | public class PublishedContentByTypeQuery
4 | {
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Types/PublishedContent/PublishedContentQuery.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Our.Umbraco.GraphQL.Attributes;
3 | using Umbraco.Cms.Core.Models.PublishedContent;
4 | using Umbraco.Cms.Core.PublishedCache;
5 | using Umbraco.Extensions;
6 |
7 | namespace Our.Umbraco.GraphQL.Types.PublishedContent
8 | {
9 | public class PublishedContentQuery
10 | {
11 | [NonNull]
12 | public PublishedContentAtRootQuery AtRoot([Inject] PublishedContentAtRootQuery query) => query;
13 |
14 | public IPublishedContent ById([Inject] IPublishedSnapshotAccessor snapshotAccessor, Id id, string culture = null) =>
15 | GetInternal(snapshotAccessor, x => x.GetById(id.As()), culture);
16 |
17 | [NonNull]
18 | public PublishedContentByTypeQuery ByType([Inject] PublishedContentByTypeQuery query) => query;
19 |
20 | public IPublishedContent ByUrl([Inject] IPublishedSnapshotAccessor snapshotAccessor, string url, string culture = null) =>
21 | GetInternal(snapshotAccessor, x => x.GetByRoute(url, culture: culture), culture);
22 |
23 | private static IPublishedContent GetInternal(IPublishedSnapshotAccessor snapshotAccessor, Func fetch, string culture)
24 | {
25 | if (!snapshotAccessor.TryGetPublishedSnapshot(out var publishedSnapshot))
26 | {
27 | throw new InvalidOperationException("Wasn't possible to a get a valid Snapshot");
28 | }
29 |
30 | var content = fetch(publishedSnapshot.Content);
31 | if (culture == null || content != null && content.IsInvariantOrHasCulture(culture))
32 | return content;
33 |
34 | return null;
35 | }
36 | }
37 |
38 | public class ExtendUmbracoQueryWithPublishedContentQuery
39 | {
40 | [NonNull]
41 | [Description("Published content in Umbraco")]
42 | public PublishedContentQuery Content([Inject] PublishedContentQuery query) => query;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Types/PublishedContent/UmbracoQuery.cs:
--------------------------------------------------------------------------------
1 | using Our.Umbraco.GraphQL.Attributes;
2 |
3 | namespace Our.Umbraco.GraphQL.Types.PublishedContent
4 | {
5 | public class UmbracoQuery
6 | {
7 | }
8 |
9 | public class ExtendQueryWithUmbracoQuery
10 | {
11 | [NonNull]
12 | [Description("Query various types of data from the Umbraco CMS")]
13 | public UmbracoQuery Umbraco([Inject] UmbracoQuery query) => query;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Types/Query.cs:
--------------------------------------------------------------------------------
1 | namespace Our.Umbraco.GraphQL.Types
2 | {
3 | public class Query
4 | {
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Types/Relay/Connection.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 |
4 | namespace Our.Umbraco.GraphQL.Types.Relay
5 | {
6 | public class Connection
7 | {
8 | public long? TotalCount { get; set; }
9 | public PageInfo PageInfo { get; set; }
10 | public List> Edges { get; set; }
11 | public List Items => Edges?.Select(x => x.Node).ToList();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Types/Relay/Edge.cs:
--------------------------------------------------------------------------------
1 | namespace Our.Umbraco.GraphQL.Types.Relay
2 | {
3 | public class Edge
4 | {
5 | public string Cursor { get; set; }
6 | public T Node { get; set; }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Types/Relay/PageInfo.cs:
--------------------------------------------------------------------------------
1 | namespace Our.Umbraco.GraphQL.Types.Relay
2 | {
3 | public class PageInfo
4 | {
5 | public string EndCursor { get; set; }
6 | public bool HasNextPage { get; set; }
7 | public bool HasPreviousPage { get; set; }
8 | public string StartCursor { get; set; }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Types/Schema.cs:
--------------------------------------------------------------------------------
1 | namespace Our.Umbraco.GraphQL.Types
2 | {
3 | public class Schema
4 | {
5 | public TQuery Query { get; set; }
6 | }
7 | public class Schema
8 | {
9 | public TQuery Query { get; set; }
10 | public TMutation Mutation { get; set; }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Types/SortOrder.cs:
--------------------------------------------------------------------------------
1 | namespace Our.Umbraco.GraphQL.Types
2 | {
3 | public enum SortOrder
4 | {
5 | Ascending,
6 | Descending
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/Web/GraphQLServerOptions.cs:
--------------------------------------------------------------------------------
1 | using GraphQL.Server.Ui.Playground;
2 | using GraphQL.Validation.Complexity;
3 |
4 | namespace Our.Umbraco.GraphQL.Web
5 | {
6 | public class GraphQLServerOptions
7 | {
8 | public string Path { get; set; } = "/umbraco/graphql";
9 | public bool EnableMetrics { get; set; }
10 | public bool EnablePlayground { get; set; }
11 | public bool EnableCors { get; set; }
12 | public string CorsPolicyName { get; set; }
13 | public string[] CorsAllowedOrigins { get; set; }
14 | public string[] CorsAllowedExposedHeaders { get; set; }
15 | public string[] CorsAllowedHeaders { get; set; }
16 | public string[] CorsAllowedMethods { get; set; }
17 | public ComplexityConfiguration Complexity { get; set; } = new ComplexityConfiguration();
18 | public PlaygroundOptions Playground { get; set; } = new PlaygroundOptions { GraphQLEndPoint = "/umbraco/graphql", SubscriptionsEndPoint = "/umbraco/graphql" };
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/content/App_Start/GraphQLComponent.cs.pp:
--------------------------------------------------------------------------------
1 | using System.Web.Hosting;
2 | using Our.Umbraco.GraphQL.Web;
3 | using Owin;
4 | using Umbraco.Cms.Core.Configuration;
5 | using Umbraco.Cms.Core.Composing;
6 | using Umbraco.Cms.Core;
7 | using Umbraco.Web;
8 |
9 | namespace $rootnamespace$
10 | {
11 | [RuntimeLevel(MinLevel = RuntimeLevel.Run)]
12 | public class GraphQLComposer : ComponentComposer, IUserComposer
13 | {
14 | }
15 |
16 | public class GraphQLComponent : IComponent
17 | {
18 | private readonly IGlobalSettings _globalSettings;
19 | private readonly IFactory _factory;
20 |
21 | public GraphQLComponent(IGlobalSettings globalSettings, IFactory factory)
22 | {
23 | _globalSettings = globalSettings ?? throw new System.ArgumentNullException(nameof(globalSettings));
24 | _factory = factory ?? throw new System.ArgumentNullException(nameof(factory));
25 | }
26 |
27 | public void Initialize()
28 | {
29 | UmbracoDefaultOwinStartup.MiddlewareConfigured += UmbracoDefaultOwinStartup_MiddlewareConfigured;
30 | }
31 |
32 | private void UmbracoDefaultOwinStartup_MiddlewareConfigured(object sender, OwinMiddlewareConfiguredEventArgs e) =>
33 | Configure(e.AppBuilder);
34 |
35 | private void Configure(IAppBuilder app)
36 | {
37 | var path = $"/{_globalSettings.GetUmbracoMvcArea()}/graphql";
38 |
39 | app.UseUmbracoGraphQL(path, _factory, opts =>
40 | {
41 | opts.Debug = HostingEnvironment.IsDevelopmentEnvironment;
42 | opts.EnableMetrics = true;
43 | opts.EnableMiniProfiler = false;
44 | opts.EnablePlayground = true;
45 | });
46 | }
47 |
48 | public void Terminate()
49 | {
50 | UmbracoDefaultOwinStartup.MiddlewareConfigured -= UmbracoDefaultOwinStartup_MiddlewareConfigured;
51 | }
52 | }
53 | }
--------------------------------------------------------------------------------
/src/Our.Umbraco.GraphQL/readme.txt:
--------------------------------------------------------------------------------
1 | _____ _ _____ _ __ _ _ _
2 | | __ \ | | | _ | | / _| | | | | | |
3 | | | \/_ __ __ _ _ __ | |__ | | | | | | |_ ___ _ __ | | | |_ __ ___ | |__ _ __ __ _ ___ ___
4 | | | __| '__/ _` | '_ \| '_ \| | | | | | _/ _ \| '__| | | | | '_ ` _ \| '_ \| '__/ _` |/ __/ _ \
5 | | |_\ \ | | (_| | |_) | | | \ \/' / |____ | || (_) | | | |_| | | | | | | |_) | | | (_| | (_| (_) |
6 | \____/_| \__,_| .__/|_| |_|\_/\_\_____/ |_| \___/|_| \___/|_| |_| |_|_.__/|_| \__,_|\___\___/
7 | | |
8 | |_|
9 |
10 | This package currently is intended for development-level testing right now.
11 |
12 | All doctypes and media properties are accessible via the GraphQL endpoint by anyone, as permissions and other security features aren't yet present.
13 | Don't use this on any data you need to keep protected
14 |
15 | For more info visit https://github.com/rasmusjp/umbraco-graphql/
--------------------------------------------------------------------------------
/test/Our.Umbraco.GraphQL.Tests/Adapters/PublishedContent/Types/LinkTypeGraphTypeTests.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using Our.Umbraco.GraphQL.Adapters.PublishedContent.Types;
3 | using Umbraco.Cms.Core.Models;
4 | using Xunit;
5 |
6 | namespace Our.Umbraco.GraphQL.Tests.Adapters.PublishedContent.Types
7 | {
8 | public class ContentVariationTests
9 | {
10 | [Fact]
11 | public void Ctor_SetsName()
12 | {
13 | var sut = new ContentVariationGraphType();
14 |
15 | sut.Name.Should().Be("ContentVariation");
16 | }
17 | [Fact]
18 | public void Ctor_SetsDescription()
19 | {
20 | var sut = new ContentVariationGraphType();
21 |
22 | sut.Description.Should().Be("Indicates how values can vary.");
23 | }
24 |
25 | [Theory]
26 | [InlineData("NOTHING", ContentVariation.Nothing)]
27 | [InlineData("CULTURE", ContentVariation.Culture)]
28 | [InlineData("SEGMENT", ContentVariation.Segment)]
29 | [InlineData("CULTURE_AND_SEGMENT", ContentVariation.CultureAndSegment)]
30 | public void Ctor_AddsFields(string field, ContentVariation value)
31 | {
32 | var sut = new ContentVariationGraphType();
33 |
34 | sut.Values.Should().Contain(x => x.Name == field)
35 | .Which.Value.Should().Be(value);
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/test/Our.Umbraco.GraphQL.Tests/Adapters/PublishedContent/Types/PublishedContentCompositionGraphTypeTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using FluentAssertions;
3 | using GraphQL.Types;
4 | using GraphQL.Types.Relay;
5 | using Microsoft.AspNetCore.Http;
6 | using NSubstitute;
7 | using Our.Umbraco.GraphQL.Adapters.PublishedContent.Types;
8 | using Our.Umbraco.GraphQL.Adapters.Types.Resolution;
9 | using Umbraco.Cms.Core.Models;
10 | using Umbraco.Cms.Core.Models.PublishedContent;
11 | using Umbraco.Cms.Core.Routing;
12 | using Umbraco.Cms.Core.Web;
13 | using Xunit;
14 | using IdGraphType = Our.Umbraco.GraphQL.Adapters.Types.IdGraphType;
15 |
16 | namespace Our.Umbraco.GraphQL.Tests.Adapters.PublishedContent.Types
17 | {
18 | public class PublishedContentCompositionGraphTypeTests
19 | {
20 | private PublishedContentCompositionGraphType CreateSUT(IContentTypeComposition contentType = null)
21 | {
22 | return new PublishedContentCompositionGraphType(contentType ?? Substitute.For(),
23 | Substitute.For(), new TypeRegistry(), Substitute.For(), Substitute.For(), Substitute.For());
24 | }
25 |
26 | [Theory]
27 | [InlineData(typeof(IContentType), "person", "PersonPublishedContent")]
28 | [InlineData(typeof(IMediaType), "image", "ImagePublishedMedia")]
29 | [InlineData(typeof(IContentType), "feature", "FeaturePublishedElement", true)]
30 | public void Ctor_SetsName(Type type, string alias, string expectedName, bool isElement = false)
31 | {
32 | var contentType = (IContentTypeComposition) Substitute.For(new[] {type}, null);
33 | contentType.Alias.Returns(alias);
34 | contentType.IsElement.Returns(isElement);
35 |
36 | var graphType = CreateSUT(contentType);
37 |
38 | graphType.Name.Should().Be(expectedName);
39 | }
40 |
41 | [Theory]
42 | [InlineData("_ancestors", typeof(ConnectionType))]
43 | [InlineData("_children", typeof(ConnectionType))]
44 | [InlineData("_createDate", typeof(NonNullGraphType))]
45 | [InlineData("_creatorName", typeof(NonNullGraphType))]
46 | [InlineData("_contentType", typeof(NonNullGraphType))]
47 | [InlineData("_id", typeof(NonNullGraphType))]
48 | [InlineData("_level", typeof(NonNullGraphType))]
49 | [InlineData("_name", typeof(StringGraphType))]
50 | [InlineData("_parent", typeof(PublishedContentInterfaceGraphType))]
51 | [InlineData("_sortOrder", typeof(NonNullGraphType))]
52 | [InlineData("_url", typeof(StringGraphType))]
53 | [InlineData("_updateDate", typeof(DateTimeGraphType))]
54 | [InlineData("_writerName", typeof(NonNullGraphType))]
55 | public void Fields_Type_ShouldBeOfExpectedType(string field, Type type)
56 | {
57 | var graphType = CreateSUT();
58 |
59 | graphType.Fields.Should().Contain(x => x.Name == field)
60 | .Which.Type.Should().Be(type);
61 | }
62 |
63 | [Theory]
64 | [InlineData("_name", "culture", typeof(StringGraphType))]
65 | [InlineData("_url", "culture", typeof(StringGraphType))]
66 | [InlineData("_url", "mode", typeof(UrlModeGraphType))]
67 | [InlineData("_updateDate", "culture", typeof(StringGraphType))]
68 | public void Fields_Arguments_ShouldBeOfExpectedType(string field, string argument, Type type)
69 | {
70 | var graphType = CreateSUT();
71 |
72 | graphType.Fields.Should().Contain(x => x.Name == field)
73 | .Which.Arguments.Should().Contain(x => x.Name == argument)
74 | .Which.Type.Should().Be(type);
75 | }
76 | }
77 | }
78 |
79 |
--------------------------------------------------------------------------------
/test/Our.Umbraco.GraphQL.Tests/Adapters/PublishedContent/Types/PublishedContentInterfaceGraphTypeTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using FluentAssertions;
3 | using GraphQL.Types;
4 | using GraphQL.Types.Relay;
5 | using Our.Umbraco.GraphQL.Adapters.PublishedContent.Types;
6 | using Xunit;
7 | using IdGraphType = Our.Umbraco.GraphQL.Adapters.Types.IdGraphType;
8 |
9 | namespace Our.Umbraco.GraphQL.Tests.Adapters.PublishedContent.Types
10 | {
11 | public class PublishedContentInterfaceGraphTypeTests
12 | {
13 | [Fact]
14 | public void Ctor_SetsName()
15 | {
16 | var graphType = new PublishedContentInterfaceGraphType();
17 |
18 | graphType.Name.Should().Be("PublishedContent");
19 | }
20 |
21 | [Theory]
22 | [InlineData("_ancestors", typeof(ConnectionType))]
23 | [InlineData("_children", typeof(ConnectionType))]
24 | [InlineData("_createDate", typeof(NonNullGraphType))]
25 | [InlineData("_creatorName", typeof(NonNullGraphType))]
26 | [InlineData("_contentType", typeof(NonNullGraphType))]
27 | [InlineData("_id", typeof(NonNullGraphType))]
28 | [InlineData("_level", typeof(NonNullGraphType))]
29 | [InlineData("_name", typeof(StringGraphType))]
30 | [InlineData("_parent", typeof(PublishedContentInterfaceGraphType))]
31 | [InlineData("_sortOrder", typeof(NonNullGraphType))]
32 | [InlineData("_url", typeof(StringGraphType))]
33 | [InlineData("_updateDate", typeof(DateTimeGraphType))]
34 | [InlineData("_writerName", typeof(NonNullGraphType))]
35 | public void Fields_Type_ShouldBeOfExpectedType(string field, Type type)
36 | {
37 | var graphType = new PublishedContentInterfaceGraphType();
38 |
39 | graphType.Fields.Should().Contain(x => x.Name == field)
40 | .Which.Type.Should().Be(type);
41 | }
42 |
43 | [Theory]
44 | [InlineData("_name", "culture", typeof(StringGraphType))]
45 | [InlineData("_url", "culture", typeof(StringGraphType))]
46 | [InlineData("_url", "mode", typeof(UrlModeGraphType))]
47 | [InlineData("_updateDate", "culture", typeof(StringGraphType))]
48 | public void Fields_Arguments_ShouldBeOfExpectedType(string field, string argument, Type type)
49 | {
50 | var graphType = new PublishedContentInterfaceGraphType();
51 |
52 | graphType.Fields.Should().Contain(x => x.Name == field)
53 | .Which.Arguments.Should().Contain(x => x.Name == argument)
54 | .Which.Type.Should().Be(type);
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/test/Our.Umbraco.GraphQL.Tests/Adapters/PublishedContent/Types/PublishedElementInterfaceGraphTypeTests.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using GraphQL.Types;
3 | using Our.Umbraco.GraphQL.Adapters.PublishedContent.Types;
4 | using Xunit;
5 | using IdGraphType = Our.Umbraco.GraphQL.Adapters.Types.IdGraphType;
6 |
7 | namespace Our.Umbraco.GraphQL.Tests.Adapters.PublishedContent.Types
8 | {
9 | public class PublishedElementInterfaceGraphTypeTests
10 | {
11 | [Fact]
12 | public void Ctor_SetsName()
13 | {
14 | var graphType = new PublishedElementInterfaceGraphType();
15 |
16 | graphType.Name.Should().Be("PublishedElement");
17 | }
18 |
19 | [Fact]
20 | public void Ctor_AddsFields()
21 | {
22 | var graphType = new PublishedElementInterfaceGraphType();
23 |
24 | graphType.Fields.Should().Contain(x => x.Name == "_contentType")
25 | .And.Contain(x => x.Name == "_id");
26 | }
27 |
28 | [Fact]
29 | public void ContentTypeField_Type_ShouldBePublishedContentGraphType()
30 | {
31 | var graphType = new PublishedElementInterfaceGraphType();
32 |
33 | graphType.Fields.Should().Contain(x => x.Name == "_contentType")
34 | .Which.Type.Should().Be>();
35 | }
36 |
37 | [Fact]
38 | public void IdField_Type_ShouldBeIdGraphType()
39 | {
40 | var graphType = new PublishedElementInterfaceGraphType();
41 |
42 | graphType.Fields.Should().Contain(x => x.Name == "_id")
43 | .Which.Type.Should().Be>();
44 | }
45 |
46 | // [Fact]
47 | // public void ContentTypeFieldResolver_WhenCalled_ReturnsAlias()
48 | // {
49 | // var graphType = new PublishedElementInterfaceGraphType();
50 | //
51 | // var contentType = Substitute.For();
52 | // var element = Substitute.For();
53 | // element.ContentType.Returns(contentType);
54 | //
55 | // graphType.Fields.Should().Contain(x => x.Name == "_contentType")
56 | // .Which.Resolver.Resolve(new ResolveFieldContext{ Source = element })
57 | // .Should().Be(contentType);
58 | // }
59 | //
60 | // [Fact]
61 | // public void CompositionAliasesFieldResolver_WhenCalled_ReturnsAlias()
62 | // {
63 | // var graphType = new PublishedElementInterfaceGraphType();
64 | //
65 | // var element = Substitute.For();
66 | // element.Key.Returns(new Guid("F14EA3D9-E40A-4A14-B860-492125D6877B"));
67 | //
68 | // graphType.Fields.Should().Contain(x => x.Name == "_id")
69 | // .Which.Resolver.Resolve(new ResolveFieldContext{ Source = element })
70 | // .Should().Be(element.Key);
71 | // }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/test/Our.Umbraco.GraphQL.Tests/Adapters/PublishedContent/Types/PublishedItemTypeGraphType.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using Our.Umbraco.GraphQL.Adapters.PublishedContent.Types;
3 | using Umbraco.Cms.Core.Models.PublishedContent;
4 | using Xunit;
5 |
6 | namespace Our.Umbraco.GraphQL.Tests.Adapters.PublishedContent.Types
7 | {
8 | public class PublishedItemTypeGraphTypeTests
9 | {
10 | [Fact]
11 | public void Ctor_SetsName()
12 | {
13 | var sut = new PublishedItemTypeGraphType();
14 |
15 | sut.Name.Should().Be("PublishedItemType");
16 | }
17 | [Fact]
18 | public void Ctor_SetsDescription()
19 | {
20 | var sut = new PublishedItemTypeGraphType();
21 |
22 | sut.Description.Should().Be("The type of published element.");
23 | }
24 |
25 | [Theory]
26 | [InlineData("CONTENT", PublishedItemType.Content)]
27 | [InlineData("ELEMENT", PublishedItemType.Element)]
28 | [InlineData("MEDIA", PublishedItemType.Media)]
29 | [InlineData("MEMBER", PublishedItemType.Member)]
30 | [InlineData("UNKNOWN", PublishedItemType.Unknown)]
31 | public void Ctor_AddsFields(string field, PublishedItemType value)
32 | {
33 | var sut = new PublishedItemTypeGraphType();
34 |
35 | sut.Values.Should().Contain(x => x.Name == field)
36 | .Which.Value.Should().Be(value);
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/test/Our.Umbraco.GraphQL.Tests/Adapters/PublishedContent/Types/UrlModeGraphTypeTests.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using Our.Umbraco.GraphQL.Adapters.PublishedContent.Types;
3 | using Umbraco.Cms.Core.Models.PublishedContent;
4 | using Xunit;
5 |
6 | namespace Our.Umbraco.GraphQL.Tests.Adapters.PublishedContent.Types
7 | {
8 | public class UrlModeGraphTypeTests
9 | {
10 | [Fact]
11 | public void Ctor_SetsName()
12 | {
13 | var sut = new UrlModeGraphType();
14 |
15 | sut.Name.Should().Be("UrlMode");
16 | }
17 | [Fact]
18 | public void Ctor_SetsDescription()
19 | {
20 | var sut = new UrlModeGraphType();
21 |
22 | sut.Description.Should()
23 | .Be("Specifies the type of urls that the url provider should produce, Auto is the default.");
24 | }
25 |
26 | [Theory]
27 | [InlineData("ABSOLUTE", UrlMode.Absolute)]
28 | [InlineData("AUTO", UrlMode.Auto)]
29 | [InlineData("DEFAULT", UrlMode.Default)]
30 | [InlineData("RELATIVE", UrlMode.Relative)]
31 | public void Ctor_AddsFields(string field, UrlMode value)
32 | {
33 | var sut = new UrlModeGraphType();
34 |
35 | sut.Values.Should().Contain(x => x.Name == field)
36 | .Which.Value.Should().Be(value);
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/test/Our.Umbraco.GraphQL.Tests/Adapters/Types/GuidGraphTypeTests.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using Our.Umbraco.GraphQL.Adapters.Types;
3 | using Xunit;
4 |
5 | namespace Our.Umbraco.GraphQL.Tests.Adapters.Types
6 | {
7 | public class GuidGraphTypeTests
8 | {
9 | [Fact]
10 | public void Ctor_SetsName()
11 | {
12 | var graphType = new GuidGraphType();
13 | graphType.Name.Should().Be("Guid");
14 | }
15 |
16 | [Fact]
17 | public void Ctor_SetsDescription()
18 | {
19 | var graphType = new GuidGraphType();
20 | graphType.Description.Should().Be("Globally Unique Identifier.");
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/test/Our.Umbraco.GraphQL.Tests/Adapters/Types/HtmlGraphTypeTests.cs:
--------------------------------------------------------------------------------
1 | using System.Web;
2 | using FluentAssertions;
3 | using GraphQL.Language.AST;
4 | using Microsoft.AspNetCore.Html;
5 | using Our.Umbraco.GraphQL.Adapters.Types;
6 | using Xunit;
7 |
8 | namespace Our.Umbraco.GraphQL.Tests.Adapters.Types
9 | {
10 | public class HtmlGraphTypeTests
11 | {
12 | [Fact]
13 | public void Ctor_SetsName()
14 | {
15 | var htmlGraphType = new HtmlGraphType();
16 |
17 | htmlGraphType.Name.Should().Be("HTML");
18 | }
19 |
20 | [Fact]
21 | public void Ctor_SetsDescription()
22 | {
23 | var htmlGraphType = new HtmlGraphType();
24 |
25 | htmlGraphType.Description.Should().Be("A string containing HTML code.");
26 | }
27 |
28 | [Fact]
29 | public void Serialize_WithHtmlString_ReturnsValueToString()
30 | {
31 | var htmlGraphType = new HtmlGraphType();
32 | var value = "Some HTML
";
33 | var htmlString = new HtmlString(value);
34 |
35 | var serialized = htmlGraphType.Serialize(htmlString);
36 |
37 | serialized.Should().BeOfType().Which.Should().Be(value);
38 | }
39 |
40 | [Fact]
41 | public void Serialize_WithNull_ReturnsNull()
42 | {
43 | var htmlGraphType = new HtmlGraphType();
44 |
45 | var serialized = htmlGraphType.Serialize(null);
46 |
47 | serialized.Should().BeNull();
48 | }
49 |
50 | [Fact]
51 | public void ParseValue_WithValue_ReturnsHtmlString()
52 | {
53 | var htmlGraphType = new HtmlGraphType();
54 | var value = "Some HTML
";
55 |
56 | var parsed = htmlGraphType.ParseValue(value);
57 |
58 | parsed.Should().BeAssignableTo().Which.ToString().Should().Be(value);
59 | }
60 |
61 | [Fact]
62 | public void ParseValue_WithNull_ReturnsNull()
63 | {
64 | var htmlGraphType = new HtmlGraphType();
65 |
66 | var parsed = htmlGraphType.ParseValue(null);
67 |
68 | parsed.Should().BeNull();
69 | }
70 |
71 | [Fact]
72 | public void ParseLiteral_WithStringValue_ReturnsHtmlString()
73 | {
74 | var htmlGraphType = new HtmlGraphType();
75 | var value = "Some HTML
";
76 |
77 | var parsed = htmlGraphType.ParseLiteral(new StringValue(value));
78 |
79 | parsed.Should().BeAssignableTo().Which.ToString().Should().Be(value);
80 | }
81 |
82 | [Fact]
83 | public void ParseLiteral_WithNull_ReturnsNull()
84 | {
85 | var htmlGraphType = new HtmlGraphType();
86 |
87 | var parsed = htmlGraphType.ParseLiteral(null);
88 |
89 | parsed.Should().BeNull();
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/test/Our.Umbraco.GraphQL.Tests/Adapters/Types/IdGraphTypeTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using FluentAssertions;
3 | using GraphQL.Language.AST;
4 | using Our.Umbraco.GraphQL.Adapters.Types;
5 | using Our.Umbraco.GraphQL.Types;
6 | using Xunit;
7 |
8 | namespace Our.Umbraco.GraphQL.Tests.Adapters.Types
9 | {
10 | public class IdGraphTypeTests
11 | {
12 | [Fact]
13 | public void Serialize_WithId_ReturnsValueToString()
14 | {
15 | var idGraphType = new IdGraphType();
16 | var value = "05087385-5095-448D-AA90-4B9AD3C1CA3F";
17 | var id = new Id(value);
18 |
19 | var serialized = idGraphType.Serialize(id);
20 |
21 | serialized.Should().BeOfType().Which.Should().Be(value);
22 | }
23 |
24 | [Fact]
25 | public void Serialize_WithNull_ReturnsNull()
26 | {
27 | var idGraphType = new IdGraphType();
28 |
29 | var serialized = idGraphType.Serialize(null);
30 |
31 | serialized.Should().BeNull();
32 | }
33 |
34 | [Fact]
35 | public void ParseValue_WithValue_ReturnsId()
36 | {
37 | var idGraphType = new IdGraphType();
38 | var value = "BF389740-3EEE-4F2E-BBB1-1C4758B5CE11";
39 |
40 | var parsed = idGraphType.ParseValue(value);
41 |
42 | parsed.Should().BeOfType().Which.Value.Should().Be(value);
43 | }
44 |
45 | [Fact]
46 | public void ParseValue_WithNull_ReturnsNull()
47 | {
48 | var idGraphType = new IdGraphType();
49 |
50 | var parsed = idGraphType.ParseValue(null);
51 |
52 | parsed.Should().BeNull();
53 | }
54 |
55 | [Fact]
56 | public void ParseLiteral_WithStringValue_ReturnsId()
57 | {
58 | var idGraphType = new IdGraphType();
59 | var value = "BDCE0B55-8D23-47A4-9C66-C94F7D6D8C2A";
60 |
61 | var parsed = idGraphType.ParseLiteral(new StringValue(value));
62 |
63 | parsed.Should().BeOfType().Which.Value.Should().Be(value);
64 | }
65 |
66 | [Fact]
67 | public void ParseLiteral_WithIntValue_ReturnsId()
68 | {
69 | var idGraphType = new IdGraphType();
70 | var value = 43;
71 |
72 | var parsed = idGraphType.ParseLiteral(new IntValue(value));
73 |
74 | parsed.Should().BeOfType().Which.Value.Should().Be(value.ToString());
75 | }
76 |
77 | [Fact]
78 | public void ParseLiteral_WithNull_ReturnsNull()
79 | {
80 | var idGraphType = new IdGraphType();
81 |
82 | var parsed = idGraphType.ParseLiteral(null);
83 |
84 | parsed.Should().BeNull();
85 | }
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/test/Our.Umbraco.GraphQL.Tests/Adapters/Types/JsonGraphTypeTests.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using Our.Umbraco.GraphQL.Adapters.Types;
3 | using Xunit;
4 |
5 | namespace Our.Umbraco.GraphQL.Tests.Adapters.Types
6 | {
7 | public class JsonGraphTypeTests
8 | {
9 | [Fact]
10 | public void Ctor_SetsName()
11 | {
12 | var jsonGraphType = new JsonGraphType();
13 |
14 | jsonGraphType.Name.Should().Be("JSON");
15 | }
16 |
17 | [Fact]
18 | public void Ctor_SetsDescription()
19 | {
20 | var jsonGraphType = new JsonGraphType();
21 |
22 | jsonGraphType.Description.Should().Be("The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf).");
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/test/Our.Umbraco.GraphQL.Tests/Adapters/Types/LinkGraphTypeTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using FluentAssertions;
3 | using GraphQL.Types;
4 | using Our.Umbraco.GraphQL.Adapters.Types;
5 | using Xunit;
6 |
7 | namespace Our.Umbraco.GraphQL.Tests.Adapters.Types
8 | {
9 | public class LinkGraphTypeTests
10 | {
11 | [Fact]
12 | public void Ctor_SetsName()
13 | {
14 | var sut = new LinkGraphType();
15 |
16 | sut.Name.Should().Be("Link");
17 | }
18 |
19 | [Theory]
20 | [InlineData("name", typeof(NonNullGraphType))]
21 | [InlineData("target", typeof(StringGraphType))]
22 | [InlineData("type", typeof(NonNullGraphType))]
23 | [InlineData("url", typeof(NonNullGraphType))]
24 | [InlineData("udi", typeof(UdiGraphType))]
25 | public void Ctor_AddsFields(string field, Type type)
26 | {
27 | var sut = new LinkGraphType();
28 |
29 | sut.Fields.Should().Contain(x => x.Name == field)
30 | .Which.Type.Should().BeAssignableTo(type);
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/test/Our.Umbraco.GraphQL.Tests/Adapters/Types/LinkTypeGraphTypeTests.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using Our.Umbraco.GraphQL.Adapters.Types;
3 | using Umbraco.Cms.Core.Models;
4 | using Xunit;
5 |
6 | namespace Our.Umbraco.GraphQL.Tests.Adapters.Types
7 | {
8 | public class LinkTypeGraphTypeTests
9 | {
10 | [Fact]
11 | public void Ctor_SetsName()
12 | {
13 | var sut = new LinkTypeGraphType();
14 |
15 | sut.Name.Should().Be("LinkType");
16 | }
17 |
18 | [Theory]
19 | [InlineData("CONTENT", LinkType.Content)]
20 | [InlineData("EXTERNAL", LinkType.External)]
21 | [InlineData("MEDIA", LinkType.Media)]
22 | public void Ctor_AddsFields(string field, LinkType value)
23 | {
24 | var sut = new LinkTypeGraphType();
25 |
26 | sut.Values.Should().Contain(x => x.Name == field)
27 | .Which.Value.Should().Be(value);
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/test/Our.Umbraco.GraphQL.Tests/Adapters/Types/Relay/ConnectionGraphTypeTests.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using GraphQL.Types;
3 | using Lucene.Net.Documents;
4 | using Our.Umbraco.GraphQL.Adapters.Types.Relay;
5 | using Xunit;
6 |
7 | namespace Our.Umbraco.GraphQL.Tests.Adapters.Types.Relay
8 | {
9 | public class ConnectionGraphTypeTests
10 | {
11 |
12 | [Fact]
13 | public void Ctor_WithInstance_SetsName()
14 | {
15 | var graphType = new ConnectionGraphType(new ItemGraphType());
16 |
17 | graphType.Name.Should().Be("ItemConnection");
18 | }
19 |
20 | [Fact]
21 | public void Ctor_GenericClassWithType_SetsName()
22 | {
23 | var graphType = new ConnectionGraphType();
24 |
25 | graphType.Name.Should().Be("ItemConnection");
26 | }
27 |
28 | [Fact]
29 | public void Ctor_WithInstance_SetsResolvedType()
30 | {
31 | var itemGraphType = new ItemGraphType();
32 | var graphType = new ConnectionGraphType(itemGraphType);
33 |
34 | graphType.ResolvedType.Should().Be(itemGraphType);
35 | }
36 |
37 | [Fact]
38 | public void Ctor_WithInstance_AddsFields()
39 | {
40 | var graphType = new ConnectionGraphType(new ItemGraphType());
41 |
42 | graphType.Fields.Should().Contain(field => field.Name == "edges")
43 | .And.Contain(field => field.Name == "items")
44 | .And.Contain(field => field.Name == "pageInfo")
45 | .And.Contain(field => field.Name == "totalCount");
46 | }
47 |
48 | [Fact]
49 | public void Ctor_WithInstance_SetsEdgesResolvedType()
50 | {
51 | var graphType = new ConnectionGraphType(new ItemGraphType());
52 |
53 | graphType.Fields.Should().Contain(x => x.Name == "edges")
54 | .Which.ResolvedType.Should().BeAssignableTo()
55 | .Which.ResolvedType.Should().BeAssignableTo()
56 | .Which.ResolvedType.Should().BeAssignableTo();
57 | }
58 |
59 | [Fact]
60 | public void Ctor_WithInstance_SetsItemsResolvedType()
61 | {
62 | var graphType = new ConnectionGraphType(new ItemGraphType());
63 |
64 | graphType.Fields.Should().Contain(x => x.Name == "items")
65 | .Which.ResolvedType.Should().BeAssignableTo()
66 | .Which.ResolvedType.Should().BeAssignableTo();
67 | }
68 |
69 | private class ItemGraphType : ObjectGraphType
70 | {
71 | public ItemGraphType()
72 | {
73 | Name = "Item";
74 | }
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/test/Our.Umbraco.GraphQL.Tests/Adapters/Types/Relay/EdgeGraphTypeTests.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using GraphQL.Types;
3 | using Our.Umbraco.GraphQL.Adapters.Types.Relay;
4 | using Xunit;
5 |
6 | namespace Our.Umbraco.GraphQL.Tests.Adapters.Types.Relay
7 | {
8 | public class EdgeGraphTypeTests
9 | {
10 | [Fact]
11 | public void Ctor_WithInstance_SetsName()
12 | {
13 | var graphType = new EdgeGraphType(new ItemGraphType());
14 |
15 | graphType.Name.Should().Be("ItemEdge");
16 | }
17 |
18 | [Fact]
19 | public void Ctor_GenericClassWithType_SetsName()
20 | {
21 | var graphType = new EdgeGraphType();
22 |
23 | graphType.Name.Should().Be("ItemEdge");
24 | }
25 |
26 | [Fact]
27 | public void Ctor_WithInstance_SetsResolvedType()
28 | {
29 | var itemGraphType = new ItemGraphType();
30 | var graphType = new EdgeGraphType(itemGraphType);
31 |
32 | graphType.ResolvedType.Should().Be(itemGraphType);
33 | }
34 |
35 | [Fact]
36 | public void Ctor_WithInstance_AddsFields()
37 | {
38 | var graphType = new EdgeGraphType(new ItemGraphType());
39 |
40 | graphType.Fields.Should().SatisfyRespectively(
41 | field => field.Name.Should().Be("cursor"),
42 | field => field.Name.Should().Be("node")
43 | );
44 | }
45 |
46 | [Fact]
47 | public void Ctor_WithInstance_SetsNodeResolvedType()
48 | {
49 | var graphType = new EdgeGraphType(new ItemGraphType());
50 |
51 | graphType.Fields.Should().Contain(x => x.Name == "node")
52 | .Which.ResolvedType.Should().BeAssignableTo();
53 | }
54 |
55 | private class ItemGraphType : ObjectGraphType
56 | {
57 | public ItemGraphType()
58 | {
59 | Name = "Item";
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/test/Our.Umbraco.GraphQL.Tests/Adapters/Types/Relay/PageInfoGraphTypeTests.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using Our.Umbraco.GraphQL.Adapters.Types.Relay;
3 | using Xunit;
4 |
5 | namespace Our.Umbraco.GraphQL.Tests.Adapters.Types.Relay
6 | {
7 | public class PageInfoGraphTypeTests
8 | {
9 | [Fact]
10 | public void Ctor_SetsName()
11 | {
12 | var graphType = new PageInfoGraphType();
13 |
14 | graphType.Name.Should().Be("PageInfo");
15 | }
16 |
17 | [Fact]
18 | public void Ctor_AddsFields()
19 | {
20 | var graphType = new PageInfoGraphType();
21 |
22 | graphType.Fields.Should().Contain(field => field.Name == "endCursor")
23 | .And.Contain(field => field.Name == "hasNextPage")
24 | .And.Contain(field => field.Name == "hasPreviousPage")
25 | .And.Contain(field => field.Name == "startCursor");
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/test/Our.Umbraco.GraphQL.Tests/Adapters/Types/UdiGraphTypeTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Reflection;
3 | using FluentAssertions;
4 | using GraphQL.Language.AST;
5 | using Our.Umbraco.GraphQL.Adapters.Types;
6 | using Umbraco.Cms.Core;
7 | using Xunit;
8 |
9 | namespace Our.Umbraco.GraphQL.Tests.Adapters.Types
10 | {
11 | public class UdiGraphTypeTests
12 | {
13 | public UdiGraphTypeTests()
14 | {
15 | // we need to set _scanned to true to avoid Udi to try scanning for types
16 | // which uses the static `Current` service locator.
17 | typeof(Udi).GetField("_scanned", BindingFlags.NonPublic | BindingFlags.Static)
18 | .SetValue(null, true);
19 | }
20 |
21 | [Fact]
22 | public void Ctor_SetsName()
23 | {
24 | var udiGraphType = new UdiGraphType();
25 |
26 | udiGraphType.Name.Should().Be("UDI");
27 | }
28 |
29 | [Fact]
30 | public void Ctor_SetsDescription()
31 | {
32 | var udiGraphType = new UdiGraphType();
33 |
34 | udiGraphType.Description.Should().Be("Represents an entity identifier.");
35 | }
36 |
37 | [Fact]
38 | public void Serialize_WithUdi_ReturnsValueToString()
39 | {
40 | var udiGraphType = new UdiGraphType();
41 | var value = new Guid("{A2A6F423-7C73-4B82-A86B-D8078F81E258}");
42 | var udi = new GuidUdi("document", value);
43 |
44 | var serialized = udiGraphType.Serialize(udi);
45 |
46 | serialized.Should().BeOfType().Which.Should().Be(udi.ToString());
47 | }
48 |
49 | [Fact]
50 | public void Serialize_WithNull_ReturnsNull()
51 | {
52 | var udiGraphType = new UdiGraphType();
53 |
54 | var serialized = udiGraphType.Serialize(null);
55 |
56 | serialized.Should().BeNull();
57 | }
58 |
59 | [Fact]
60 | public void ParseValue_WithUdiValue_ReturnsUdi()
61 | {
62 | var udiGraphType = new UdiGraphType();
63 | var value = "umb://document/c0126770c4dd4c80b48464c5f38658c1";
64 |
65 | var parsed = udiGraphType.ParseValue(value);
66 |
67 | parsed.Should().BeAssignableTo