├── docs
├── search.json
├── docsets
│ ├── ContentfulDeliveryAPI.docset
│ │ └── Contents
│ │ │ ├── Resources
│ │ │ ├── Documents
│ │ │ │ ├── search.json
│ │ │ │ ├── img
│ │ │ │ │ ├── gh.png
│ │ │ │ │ ├── carat.png
│ │ │ │ │ └── dash.png
│ │ │ │ └── js
│ │ │ │ │ └── jazzy.js
│ │ │ └── docSet.dsidx
│ │ │ └── Info.plist
│ └── ContentfulDeliveryAPI.tgz
├── img
│ ├── dash.png
│ ├── gh.png
│ └── carat.png
├── undocumented.json
├── badge.svg
└── js
│ └── jazzy.js
├── .env
├── .envrc
├── Tests
├── Data
│ ├── Recordings
│ │ ├── ClientConfiguration.json
│ │ ├── ComplexSyncTests.json
│ │ └── UtilityTests.json
│ ├── SyncTests
│ │ ├── space-for-empty.json
│ │ ├── space.json
│ │ ├── deleted.json
│ │ ├── deleted-asset.json
│ │ ├── content-types-for-empty.json
│ │ ├── update-for-empty.json
│ │ ├── initial-for-empty.json
│ │ ├── added.json
│ │ ├── added-asset.json
│ │ ├── asset-multiple-locales.json
│ │ ├── initialWithoutToken.json
│ │ ├── initial.json
│ │ ├── update.json
│ │ └── all-content-types.json
│ ├── ComplexSyncTests
│ │ ├── space.json
│ │ ├── ComplexLinkTestUpdate1.json
│ │ ├── AddContentTypesContentTypes.json
│ │ ├── LinkTestResolve.json
│ │ ├── AssetTestResolve2.json
│ │ ├── NewEntryAndDeletionResolve2.json
│ │ ├── AddContentTypesUpdate.json
│ │ ├── AssetTestResolve.json
│ │ ├── NewEntryAndDeletionResolve.json
│ │ ├── AssetTestUpdate.json
│ │ ├── ComplexLinkTestUpdate2.json
│ │ ├── ComplexLinkTestContentTypes2.json
│ │ ├── LinkTestUpdate.json
│ │ ├── NewEntryAndDeletionUpdate.json
│ │ ├── LinkTestInitial.json
│ │ ├── ComplexLinkTestEntries.json
│ │ ├── ComplexLinkTestContentTypes.json
│ │ └── AssetTestInitial.json
│ └── Fixtures
│ │ ├── Crash-001.json
│ │ └── ContentType-001.json
├── FakeNavigationController.h
├── Tests-Info.plist
├── SyncBaseTestCase.h
├── FakeNavigationController.m
├── ContentfulBaseTestCase.h
├── RobustnessTests.m
├── PreviewModeSyncTests.m
├── StagingTests.m
├── LocaleTests.m
├── LinkedData.xcdatamodeld
│ └── LinkedData.xcdatamodel
│ │ └── contents
├── AddContentTypesSyncTests.m
├── LocalizedModel.xcdatamodeld
│ └── LocalizedModel.xcdatamodel
│ │ └── contents
├── LinkedAssetSyncTest.m
├── ComplexSyncTests.m
├── NewEntryAndDeletionSyncTest.m
├── SyncSpecificContentTests.m
└── ClientConfiguration.m
├── Screenshots
├── Frameworks.png
├── GeneralTab.png
└── SearchForFramework.png
├── .slather.yml
├── scripts
├── unarcify-headers.sh
├── set-delivery-version.sh
├── travis-build-test.sh
└── reference-docs.sh
├── ContentfulSDK.xcodeproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
└── xcshareddata
│ └── xcschemes
│ ├── ManagementTests.xcscheme
│ ├── CoreDataExample.xcscheme
│ ├── DeliveryTests.xcscheme
│ ├── ContentfulManagementAPI.xcscheme
│ └── ContentfulDeliveryAPI.xcscheme
├── Versions.h
├── ContentfulDeliveryAPI
├── Resources
│ ├── CDADeletedAsset.h
│ ├── CDADeletedEntry.h
│ ├── CDADeletedAsset.m
│ ├── CDADeletedEntry.m
│ ├── CDAError+Private.h
│ ├── CDASpace+Private.h
│ ├── CDAOrganizationContainer.h
│ ├── CDAArray+Private.h
│ ├── CDAError.h
│ ├── CDASpace.h
│ ├── CDAEntry+Private.h
│ ├── CDAArray.h
│ ├── CDAContentType.h
│ ├── CDAResource+Private.h
│ ├── CDASpace.m
│ ├── CDAError.m
│ ├── CDAEntry.h
│ ├── CDAResource.h
│ └── CDAContentType.m
├── CDAInputSanitizer.h
├── CDAConfiguration+Private.h
├── CDAResponse+Private.h
├── CDALocalizablePersistedEntry.m
├── CDAFallbackDictionary.h
├── CDARequestSerializer.h
├── CDARequest+Private.h
├── CDAResponseSerializer.h
├── CDAResponse.h
├── CDASyncedSpace+Private.h
├── CDANullabilityStubs.h
├── CDAFieldValueTransformer.h
├── CDAPersistedEntry.h
├── CDAField+Private.h
├── CDALocalizedPersistedEntry.h
├── ContentfulDeliveryAPI.h
├── CDAPersistedSpace.h
├── CDAContentTypeRegistry.h
├── CDAResponse.m
├── CDAUtilities.h
├── CDALocalizablePersistedEntry.h
├── CDAConfiguration.m
├── CDAInputSanitizer.m
├── CDAPersistedAsset.h
├── CDARequest.h
├── CDAFallbackDictionary.m
├── CDARequest.m
├── CDAContentTypeRegistry.m
├── CDARequestOperationManager.h
├── CDAConfiguration.h
├── CDAField.h
├── CDAClient+Private.h
├── CDARequestSerializer.m
└── CDAFieldValueTransformer.m
├── Gemfile
├── ContentfulSDK.xcworkspace
└── contents.xcworkspacedata
├── .gitignore
├── LICENSE
├── Podfile
├── .travis.yml
├── ContentfulDeliveryAPI.podspec
├── Podfile.lock
└── Makefile
/docs/search.json:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/.env:
--------------------------------------------------------------------------------
1 | DELIVERY_SDK_VERSION=3.0.0
2 |
3 |
--------------------------------------------------------------------------------
/.envrc:
--------------------------------------------------------------------------------
1 | export DELIVERY_SDK_VERSION=3.0.0
2 |
--------------------------------------------------------------------------------
/Tests/Data/Recordings/ClientConfiguration.json:
--------------------------------------------------------------------------------
1 | [
2 |
3 | ]
--------------------------------------------------------------------------------
/docs/docsets/ContentfulDeliveryAPI.docset/Contents/Resources/Documents/search.json:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/docs/img/dash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/contentful/contentful.objc/master/docs/img/dash.png
--------------------------------------------------------------------------------
/docs/img/gh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/contentful/contentful.objc/master/docs/img/gh.png
--------------------------------------------------------------------------------
/docs/img/carat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/contentful/contentful.objc/master/docs/img/carat.png
--------------------------------------------------------------------------------
/Screenshots/Frameworks.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/contentful/contentful.objc/master/Screenshots/Frameworks.png
--------------------------------------------------------------------------------
/Screenshots/GeneralTab.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/contentful/contentful.objc/master/Screenshots/GeneralTab.png
--------------------------------------------------------------------------------
/Screenshots/SearchForFramework.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/contentful/contentful.objc/master/Screenshots/SearchForFramework.png
--------------------------------------------------------------------------------
/docs/docsets/ContentfulDeliveryAPI.tgz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/contentful/contentful.objc/master/docs/docsets/ContentfulDeliveryAPI.tgz
--------------------------------------------------------------------------------
/docs/undocumented.json:
--------------------------------------------------------------------------------
1 | {
2 | "warnings": [
3 |
4 | ],
5 | "source_directory": "/Users/jpwright/Contentful/objc/SDK/contentful.objc"
6 | }
--------------------------------------------------------------------------------
/.slather.yml:
--------------------------------------------------------------------------------
1 | coverage_service: coveralls
2 | workspace: ContentfulSDK.xcworkspace
3 | xcodeproj: ContentfulSDK.xcodeproj
4 | scheme: "ContentfulDeliveryAPI"
5 | ignore:
6 | - Examples/*
7 | - Tests/*
8 |
--------------------------------------------------------------------------------
/docs/docsets/ContentfulDeliveryAPI.docset/Contents/Resources/docSet.dsidx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/contentful/contentful.objc/master/docs/docsets/ContentfulDeliveryAPI.docset/Contents/Resources/docSet.dsidx
--------------------------------------------------------------------------------
/docs/docsets/ContentfulDeliveryAPI.docset/Contents/Resources/Documents/img/gh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/contentful/contentful.objc/master/docs/docsets/ContentfulDeliveryAPI.docset/Contents/Resources/Documents/img/gh.png
--------------------------------------------------------------------------------
/docs/docsets/ContentfulDeliveryAPI.docset/Contents/Resources/Documents/img/carat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/contentful/contentful.objc/master/docs/docsets/ContentfulDeliveryAPI.docset/Contents/Resources/Documents/img/carat.png
--------------------------------------------------------------------------------
/docs/docsets/ContentfulDeliveryAPI.docset/Contents/Resources/Documents/img/dash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/contentful/contentful.objc/master/docs/docsets/ContentfulDeliveryAPI.docset/Contents/Resources/Documents/img/dash.png
--------------------------------------------------------------------------------
/scripts/unarcify-headers.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | sed -i '' 's/(nonatomic) BOOL/(nonatomic, assign) BOOL/' *.h
4 | sed -i '' 's/(nonatomic) CDAResourceType/(nonatomic, assign) CDAResourceType/' *.h
5 | sed -i '' 's/(nonatomic)/(nonatomic, retain)/' *.h
6 |
--------------------------------------------------------------------------------
/ContentfulSDK.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Versions.h:
--------------------------------------------------------------------------------
1 | //
2 | // Versions.h
3 | // ContentfulSDK
4 | //
5 | // Created by JP Wright on 26.05.17.
6 | //
7 | //
8 |
9 | #ifndef Versions_h
10 | #define Versions_h
11 |
12 | #define DELIVERY_SDK_VERSION @"3.0.0"
13 |
14 | #endif /* Versions_h */
15 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/Resources/CDADeletedAsset.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDADeletedAsset.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 26/03/14.
6 | //
7 | //
8 |
9 | #import "CDAResource.h"
10 |
11 | @interface CDADeletedAsset : CDAResource
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/Resources/CDADeletedEntry.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDADeletedEntry.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 26/03/14.
6 | //
7 | //
8 |
9 | #import "CDAResource.h"
10 |
11 | @interface CDADeletedEntry : CDAResource
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/scripts/set-delivery-version.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | sed -i '' 's%\(^.*DELIVERY_SDK_VERSION @"\)\(.*\)\("\)%\1'$1'\3%g' Versions.h
4 | sed -i '' 's%\(^.*DELIVERY_SDK_VERSION=\)\(.*\)%\1'$1'%g' .env
5 | sed -i '' 's%\(^.*DELIVERY_SDK_VERSION=\)\(.*\)%\1'$1'%g' .envrc
6 | direnv allow
7 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'http://rubygems.org'
2 |
3 | gem 'cocoapods'
4 | gem 'xcpretty'
5 | gem 'xcode-install'
6 | gem 'cocoapods-packager'
7 | gem 'cocoapods-docstats'
8 | gem 'cocoapods-deintegrate'
9 | gem 'cocoapods-clean'
10 | gem 'slather'
11 | gem 'jazzy'
12 | gem 'dotenv'
13 |
14 |
--------------------------------------------------------------------------------
/Tests/Data/SyncTests/space-for-empty.json:
--------------------------------------------------------------------------------
1 | {
2 | "sys": {
3 | "type": "Space",
4 | "id": "a7uc4j82xa5d"
5 | },
6 | "name": "testtestets",
7 | "locales": [
8 | {
9 | "code": "en-US",
10 | "default": true,
11 | "name": "U.S. English"
12 | }
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/Tests/Data/SyncTests/space.json:
--------------------------------------------------------------------------------
1 | {
2 | "sys": {
3 | "type": "Space",
4 | "id": "emh6o2ireilu"
5 | },
6 | "name": "Test Space for Sync API",
7 | "locales": [
8 | {
9 | "code": "en-US",
10 | "default": true,
11 | "name": "U.S. English"
12 | }
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/Tests/FakeNavigationController.h:
--------------------------------------------------------------------------------
1 | //
2 | // FakeNavigationController.h
3 | // ContentfulSDK
4 | //
5 | // Created by JP Wright on 13/01/2017.
6 | //
7 | //
8 |
9 | #ifndef FakeNavigationController_h
10 | #define FakeNavigationController_h
11 |
12 |
13 | #endif /* FakeNavigationController_h */
14 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/CDAInputSanitizer.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDAInputSanitizer.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 09/05/14.
6 | //
7 | //
8 |
9 | @import Foundation;
10 |
11 | @interface CDAInputSanitizer : NSObject
12 |
13 | +(id)sanitizeObject:(id)object;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/Tests/Data/ComplexSyncTests/space.json:
--------------------------------------------------------------------------------
1 | {
2 | "sys": {
3 | "type": "Space",
4 | "id": "emh6o2ireilu"
5 | },
6 | "name": "Test Space for Sync API",
7 | "locales": [
8 | {
9 | "code": "en-US",
10 | "default": true,
11 | "name": "U.S. English"
12 | }
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/ContentfulSDK.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/CDAConfiguration+Private.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDAConfiguration.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 04/03/14.
6 | //
7 | //
8 |
9 | #import "CDAConfiguration.h"
10 |
11 | @interface CDAConfiguration (Private)
12 |
13 | @property (nonatomic) BOOL usesManagementAPI;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/CDAResponse+Private.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDAResponse+Private.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 04/03/14.
6 | //
7 | //
8 |
9 | #import "CDAResponse.h"
10 |
11 | @interface CDAResponse ()
12 |
13 | +(instancetype)responseWithHTTPURLResponse:(NSHTTPURLResponse*)response;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/Resources/CDADeletedAsset.m:
--------------------------------------------------------------------------------
1 | //
2 | // CDADeletedAsset.m
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 26/03/14.
6 | //
7 | //
8 |
9 | #import "CDADeletedAsset.h"
10 |
11 | @implementation CDADeletedAsset
12 |
13 | +(NSString*)CDAType {
14 | return @"DeletedAsset";
15 | }
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/Resources/CDADeletedEntry.m:
--------------------------------------------------------------------------------
1 | //
2 | // CDADeletedEntry.m
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 26/03/14.
6 | //
7 | //
8 |
9 | #import "CDADeletedEntry.h"
10 |
11 | @implementation CDADeletedEntry
12 |
13 | +(NSString*)CDAType {
14 | return @"DeletedEntry";
15 | }
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/CDALocalizablePersistedEntry.m:
--------------------------------------------------------------------------------
1 | //
2 | // CDALocalizablePersistedEntry.m
3 | //
4 | //
5 | // Created by Boris Bügling on 23/09/15.
6 | //
7 | //
8 |
9 | #import "CDALocalizablePersistedEntry.h"
10 |
11 | @implementation CDALocalizablePersistedEntry
12 |
13 | @dynamic identifier;
14 | @dynamic localizedEntries;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/CDAFallbackDictionary.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDAFallbackDictionary.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 28/03/14.
6 | //
7 | //
8 |
9 | @import Foundation;
10 |
11 | @interface CDAFallbackDictionary : NSDictionary
12 |
13 | -(instancetype)initWithDictionary:(NSDictionary *)dict fallbackDictionary:(NSDictionary*)fallbackDict;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/Resources/CDAError+Private.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDAError.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 05/03/14.
6 | //
7 | //
8 |
9 | #import "CDAError.h"
10 |
11 | @interface CDAError (Private)
12 |
13 | +(NSError*)buildErrorWithCode:(NSInteger)code userInfo:(NSDictionary*)userInfo;
14 |
15 | -(NSError*)errorRepresentationWithCode:(NSInteger)code;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/Resources/CDASpace+Private.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDASpace+Private.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 06/03/14.
6 | //
7 | //
8 |
9 | #import "CDASpace.h"
10 |
11 | @interface CDASpace ()
12 |
13 | @property (nonatomic) NSString* defaultLocale;
14 | @property (nonatomic, readonly) NSArray* localeCodes;
15 | @property (nonatomic) NSArray* locales;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/CDARequestSerializer.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDARequestSerializer.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 21/07/14.
6 | //
7 | //
8 |
9 | #import
10 |
11 | @interface CDARequestSerializer : AFJSONRequestSerializer
12 |
13 | @property (nonatomic) NSString* userAgent;
14 |
15 | -(instancetype)initWithAccessToken:(NSString*)accessToken;
16 | @end
17 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/Resources/CDAOrganizationContainer.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDAOrganizationContainer.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 29/07/14.
6 | //
7 | //
8 |
9 | #if __has_feature(modules)
10 | @import Foundation;
11 | #else
12 | #import
13 | #endif
14 |
15 |
16 | @protocol CDAOrganizationContainer
17 |
18 | @property (nonatomic) NSArray* organizations;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/CDARequest+Private.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDARequest+Private.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 10/03/14.
6 | //
7 | //
8 |
9 | #if __has_feature(modules)
10 | @import Foundation;
11 | #else
12 | #import
13 | #endif
14 |
15 | #import "CDARequest.h"
16 |
17 | @interface CDARequest ()
18 |
19 | -(instancetype)initWithSessionTask:(NSURLSessionTask *)task;
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Appledoc
2 |
3 | doc
4 |
5 | ## OS X
6 |
7 | .DS_Store
8 |
9 | ## Cocoapods
10 | Pods/
11 |
12 | ### Seed database
13 | Examples/SeedDatabase/*/Pods
14 |
15 | .pt
16 | Examples/ContentfulDeliveryAPI.zip
17 | Examples/UFO.zip
18 | Examples/UFO/Distribution/ContentfulDeliveryAPI.framework/
19 | compile_commands.json
20 | .gutter.json
21 |
22 | ## Xcode
23 |
24 | *.gcda
25 | *.gcno
26 | *.xccheckout
27 | xcuserdata
28 | .idea
29 | *.xcscmblueprint
30 |
31 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/CDAResponseSerializer.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDAResponseSerializer.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 04/03/14.
6 | //
7 | //
8 |
9 | #import
10 |
11 | @class CDAClient;
12 |
13 | @interface CDAResponseSerializer : AFJSONResponseSerializer
14 |
15 | @property (nonatomic, weak, readonly) CDAClient* client;
16 |
17 | -(instancetype)initWithClient:(CDAClient*)client;
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/CDAResponse.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDAResponse.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 04/03/14.
6 | //
7 | //
8 |
9 | #if __has_feature(modules)
10 | @import Foundation;
11 | #else
12 | #import
13 | #endif
14 |
15 | /**
16 | A `CDAResponse` encapsulates meta-information about a reponse received from the server, such as the
17 | HTTP status code or headers.
18 | */
19 | @interface CDAResponse : NSHTTPURLResponse
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/Resources/CDAArray+Private.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDAArray+Private.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 04/03/14.
6 | //
7 | //
8 |
9 | #import "CDAArray.h"
10 |
11 | @interface CDAArray ()
12 |
13 | @property (nonatomic, readonly) NSURL* nextPageUrl;
14 | @property (nonatomic, readonly) NSURL* nextSyncUrl;
15 | @property (nonatomic) NSDictionary* query;
16 |
17 | -(instancetype)initWithItems:(NSArray*)items client:(CDAClient*)client;
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/scripts/travis-build-test.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -x -o pipefail
4 |
5 | # -jobs -- specify the number of concurrent jobs
6 | # `sysctl -n hw.ncpu` -- fetch number of 'logical' cores in macOS machine
7 | xcodebuild -jobs `sysctl -n hw.ncpu` test -workspace ContentfulSDK.xcworkspace -scheme ContentfulDeliveryAPI \
8 | -sdk ${IOS_SDK} -destination "platform=iOS Simulator,name=${DEVICE_NAME},OS=${IOS_VERSION}" \
9 | ONLY_ACTIVE_ARCH=NO CODE_SIGNING_IDENTITY="" CODE_SIGNING_REQUIRED=NO | xcpretty -c
10 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/CDASyncedSpace+Private.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDASyncedSpace+Private.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 25/03/14.
6 | //
7 | //
8 |
9 | #import "CDASyncedSpace.h"
10 |
11 | @interface CDASyncedSpace ()
12 |
13 | @property (nonatomic, weak) CDAClient* client;
14 | @property (nonatomic) NSURL* nextPageUrl;
15 | @property (nonatomic) NSURL* nextSyncUrl;
16 |
17 | -(instancetype)initWithAssets:(NSArray*)assets entries:(NSArray*)entries;
18 | -(void)updateLastSyncTimestamp;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/CDANullabilityStubs.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDANullabilityStubs.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 15/04/15.
6 | //
7 | //
8 |
9 | // Thanks to https://gist.github.com/steipete/d9f519858fe5fb5533eb
10 | #if !__has_feature(nullability)
11 | #define NS_ASSUME_NONNULL_BEGIN
12 | #define NS_ASSUME_NONNULL_END
13 | #define nullable
14 | #define nonnull
15 | #define null_unspecified
16 | #define null_resettable
17 | #define __nullable
18 | #define __nonnull
19 | #define __null_unspecified
20 | #endif
21 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/CDAFieldValueTransformer.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDAFieldValueTransformer.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 09/03/14.
6 | //
7 | //
8 |
9 | #import "CDAField.h"
10 |
11 | @class CDAClient;
12 |
13 | @interface CDAFieldValueTransformer : NSValueTransformer
14 |
15 | @property (nonatomic) CDAFieldType itemType;
16 |
17 | +(instancetype)transformerOfType:(CDAFieldType)type
18 | client:(CDAClient*)client
19 | localizationAvailable:(BOOL)localizationAvailable;
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/CDAPersistedEntry.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDAPersistedEntry.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 14/04/14.
6 | //
7 | //
8 |
9 | #if __has_feature(modules)
10 | @import Foundation;
11 | #else
12 | #import
13 | #endif
14 |
15 | /**
16 | * Any class representing Entries saved to a persistent store needs to conform to this protocol.
17 | */
18 | @protocol CDAPersistedEntry
19 |
20 | /** The `sys.id` of the Entry. */
21 | @property (nonatomic) NSString* identifier;
22 |
23 | @end
24 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/CDAField+Private.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDAField+Private.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 04/03/14.
6 | //
7 | //
8 |
9 | #import "CDAField.h"
10 |
11 | @class CDAClient;
12 |
13 | @interface CDAField ()
14 |
15 | @property (nonatomic) NSString* name;
16 | @property (nonatomic) CDAFieldType type;
17 |
18 | -(instancetype)initWithDictionary:(NSDictionary *)dictionary
19 | client:(CDAClient*)client
20 | localizationAvailable:(BOOL)localizationAvailable;
21 | -(id)parseValue:(id)value;
22 |
23 | @end
24 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/CDALocalizedPersistedEntry.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDALocalizedPersistedEntry.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 22/09/15.
6 | //
7 | //
8 |
9 | #if __has_feature(modules)
10 | @import Foundation;
11 | #else
12 | #import
13 | #endif
14 |
15 | #import "CDAPersistedEntry.h"
16 |
17 | /**
18 | * Any class representing localized Entries saved to a persistent store needs to conform to this
19 | * protocol.
20 | */
21 | @protocol CDALocalizedPersistedEntry
22 |
23 | /** The locale of this persisted entry */
24 | @property (nonatomic) NSString* locale;
25 |
26 | @end
27 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/ContentfulDeliveryAPI.h:
--------------------------------------------------------------------------------
1 | //
2 | // ContentfulDeliveryAPI.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 04/03/14.
6 | //
7 | //
8 |
9 | #if __has_feature(modules)
10 | @import Foundation;
11 | #else
12 | #import
13 | #endif
14 |
15 | #import "CDAArray.h"
16 | #import "CDAAsset.h"
17 | #import "CDAClient.h"
18 | #import "CDAConfiguration.h"
19 | #import "CDAContentType.h"
20 | #import "CDAEntry.h"
21 | #import "CDAError.h"
22 | #import "CDAField.h"
23 | #import "CDAPersistenceManager.h"
24 | #import "CDARequest.h"
25 | #import "CDAResponse.h"
26 | #import "CDASpace.h"
27 | #import "CDASyncedSpace.h"
28 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/CDAPersistedSpace.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDAPersistedSpace.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 14/04/14.
6 | //
7 | //
8 |
9 | #if __has_feature(modules)
10 | @import Foundation;
11 | #else
12 | #import
13 | #endif
14 |
15 | /**
16 | * Any class representing synchronized Spaces saved to a persistent store needs to conform
17 | * to this protocol.
18 | */
19 | @protocol CDAPersistedSpace
20 |
21 | /** Timestamp of the last synchronization operation. */
22 | @property (nonatomic) NSDate* lastSyncTimestamp;
23 | /** Token for the next synchronization operation. */
24 | @property (nonatomic) NSString* syncToken;
25 |
26 | @end
27 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/Resources/CDAError.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDAError.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 05/03/14.
6 | //
7 | //
8 |
9 | #import "CDANullabilityStubs.h"
10 | #import "CDAResource.h"
11 |
12 | NS_ASSUME_NONNULL_BEGIN
13 |
14 | extern NSString* const CDAErrorDomain;
15 |
16 | /**
17 | * Details about errors which occured on the server.
18 | */
19 | @interface CDAError : CDAResource
20 |
21 | /**
22 | * Detailed representation of the error.
23 | */
24 | @property (nonatomic, readonly, nullable) NSDictionary* details;
25 |
26 | /**
27 | * Short message on the cause of the error.
28 | */
29 | @property (nonatomic, readonly, nullable) NSString* message;
30 |
31 | @end
32 |
33 | NS_ASSUME_NONNULL_END
34 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/Resources/CDASpace.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDASpace.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 06/03/14.
6 | //
7 | //
8 |
9 | #import "CDANullabilityStubs.h"
10 | #import "CDAResource.h"
11 |
12 | /**
13 | Spaces are containers for Content Types, Entries and Assets.
14 | */
15 | @interface CDASpace : CDAResource
16 |
17 | /** @name Accessing Meta-Data */
18 |
19 | /** Default locale for this Space. */
20 | @property (nonatomic, readonly) NSString* __nonnull defaultLocale;
21 | /** Possible locales used for Entries in this Space. */
22 | @property (nonatomic, readonly) NSArray* __nullable locales;
23 | /** The name of this Space. */
24 | @property (nonatomic, readonly) NSString* __nullable name;
25 |
26 | @end
27 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/Resources/CDAEntry+Private.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDAEntry+Private.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 04/03/14.
6 | //
7 | //
8 |
9 | #import "CDAEntry.h"
10 |
11 | @interface CDAEntry ()
12 |
13 | -(NSArray*)findUnresolvedAssets;
14 | -(NSArray*)findUnresolvedEntries;
15 | -(NSDictionary*)localizedFields;
16 | -(void)resolveLinksWithIncludedAssets:(NSDictionary*)assets
17 | entries:(NSDictionary*)entries
18 | usingBlock:(CDAResource* (^)(CDAResource* resource, NSDictionary* assets,
19 | NSDictionary* entries))resolver;
20 | -(void)setValue:(id)value forFieldWithName:(NSString *)key;
21 |
22 | @end
23 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/CDAContentTypeRegistry.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDAContentTypeRegistry.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 04/03/14.
6 | //
7 | //
8 |
9 | @import Foundation;
10 |
11 | @class CDAContentType;
12 |
13 | @interface CDAContentTypeRegistry : NSObject
14 |
15 | @property (nonatomic, readonly) BOOL hasCustomClasses;
16 |
17 | -(void)addContentType:(CDAContentType*)contentType;
18 | -(CDAContentType*)contentTypeForIdentifier:(NSString*)identifier;
19 | -(Class)customClassForContentType:(CDAContentType*)contentType;
20 | -(void)registerClass:(Class)customClass forContentType:(CDAContentType*)contentType;
21 | -(void)registerClass:(Class)customClass forContentTypeWithIdentifier:(NSString*)identifier;
22 |
23 | @end
24 |
--------------------------------------------------------------------------------
/Tests/Tests-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundlePackageType
14 | BNDL
15 | CFBundleShortVersionString
16 | 1.0
17 | CFBundleSignature
18 | ????
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/docs/docsets/ContentfulDeliveryAPI.docset/Contents/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleIdentifier
6 | com.jazzy.contentfuldeliveryapi
7 | CFBundleName
8 | ContentfulDeliveryAPI
9 | DocSetPlatformFamily
10 | contentfuldeliveryapi
11 | isDashDocset
12 |
13 | dashIndexFilePath
14 | index.html
15 | isJavaScriptEnabled
16 |
17 | DashDocSetFamily
18 | dashtoc
19 |
20 |
21 |
--------------------------------------------------------------------------------
/docs/badge.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Tests/Data/SyncTests/deleted.json:
--------------------------------------------------------------------------------
1 | {
2 | "sys": {
3 | "type": "Array"
4 | },
5 | "items": [
6 | {
7 | "sys": {
8 | "type": "DeletedEntry",
9 | "id": "1gQ4P2tG7QaGkQwkC4a6Gg",
10 | "space": {
11 | "sys": {
12 | "type": "Link",
13 | "linkType": "Space",
14 | "id": "emh6o2ireilu"
15 | }
16 | },
17 | "revision": 1,
18 | "createdAt": "2014-03-25T11:05:16.051Z",
19 | "updatedAt": "2014-03-25T11:05:16.051Z",
20 | "deletedAt": "2014-03-25T11:05:16.051Z"
21 | }
22 | }
23 | ],
24 | "nextSyncUrl": "https://cdn.contentful.com/spaces/emh6o2ireilu/sync?sync_token=w5ZGw6JFwqZmVcKsE8Kow4grw45QdyZew5xDN04dJg3DkmBAw4XDh8OEw5o5UVhIw6nDlFjDoBxIasKIDsKIw4VcIV18GicdwoTDjCtoMiFAfcKiwrRKIsKYwrzCmMKBw4ZhwrdhwrsGa8KTwpQ6w6A"
25 | }
26 |
--------------------------------------------------------------------------------
/Tests/Data/SyncTests/deleted-asset.json:
--------------------------------------------------------------------------------
1 | {
2 | "sys": {
3 | "type": "Array"
4 | },
5 | "items": [
6 | {
7 | "sys": {
8 | "type": "DeletedAsset",
9 | "id": "2q1Ns7Oygo2mAgoweuMCAA",
10 | "space": {
11 | "sys": {
12 | "type": "Link",
13 | "linkType": "Space",
14 | "id": "emh6o2ireilu"
15 | }
16 | },
17 | "revision": 1,
18 | "createdAt": "2014-03-25T11:09:14.488Z",
19 | "updatedAt": "2014-03-25T11:09:14.488Z",
20 | "deletedAt": "2014-03-25T11:09:14.488Z"
21 | }
22 | }
23 | ],
24 | "nextSyncUrl": "https://cdn.contentful.com/spaces/emh6o2ireilu/sync?sync_token=w5ZGw6JFwqZmVcKsE8Kow4grw45QdyYHPUPDhggxwr5qw5RBbMKWw4VjOg3DumTDg0_CgsKcYsO8UcOZfMKLw4sKUcOnJcKxfDUkGWwxNMOVw4AiacK5Bmo4ScOhI0g2cXLClxTClsOyE8OOc8O3"
25 | }
26 |
--------------------------------------------------------------------------------
/scripts/reference-docs.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | echo "Generating Jazzy Reference Documentation"
4 |
5 | SDK_NAME="ContentfulDeliveryAPI"
6 | xcodebuild_arguments="--objc,ContentfulDeliveryAPI/ContentfulDeliveryAPI.h,--,-x,objective-c,-isysroot,$(xcrun --show-sdk-path),-I,$(pwd)"
7 |
8 | jazzy \
9 | --clean \
10 | --objc \
11 | --author Contentful \
12 | --author_url https://www.contentful.com \
13 | --github_url https://github.com/contentful/contentful.objc \
14 | --github-file-prefix https://github.com/contentful/contentful.objc/tree/$DELIVERY_SDK_VERSION \
15 | --module-version $DELIVERY_SDK_VERSION \
16 | --module $SDK_NAME \
17 | --umbrella-header ContentfulDeliveryAPI/ContentfulDeliveryAPI.h \
18 | --framework-root ./ContentfulDeliveryAPI/ \
19 | --sdk iphonesimulator \
20 | --theme apple
21 | # --xcodebuild-arguments ${xcodebuild_arguments} \
22 |
--------------------------------------------------------------------------------
/Tests/Data/ComplexSyncTests/ComplexLinkTestUpdate1.json:
--------------------------------------------------------------------------------
1 | {
2 | "sys": {
3 | "type": "Array"
4 | },
5 | "items": [
6 | {
7 | "sys": {
8 | "type": "DeletedEntry",
9 | "id": "5ZmiC472OAg2SY2W0QM6Gs",
10 | "space": {
11 | "sys": {
12 | "type": "Link",
13 | "linkType": "Space",
14 | "id": "emh6o2ireilu"
15 | }
16 | },
17 | "revision": 1,
18 | "createdAt": "2014-04-11T11:40:02.150Z",
19 | "updatedAt": "2014-04-11T11:40:02.150Z",
20 | "deletedAt": "2014-04-11T11:40:02.150Z"
21 | }
22 | }
23 | ],
24 | "nextSyncUrl": "https://cdn.contentful.com/spaces/emh6o2ireilu/sync?sync_token=w5ZGw6JFwqZmVcKsE8Kow4grw45QdyY9wrEfW8KYwpROLH55G8O-U2rCq8OsQn3DvcOrw4cGwpkjIAvDgWxYwrITw4xUa8O4UCXDojMJDk8fw6RzSMK6J2vDqMOUJm_CiMKaw6lVF1jCg2vCosOFwpo"
25 | }
26 |
--------------------------------------------------------------------------------
/Tests/Data/ComplexSyncTests/AddContentTypesContentTypes.json:
--------------------------------------------------------------------------------
1 | {
2 | "sys": {
3 | "type": "Array"
4 | },
5 | "total": 1,
6 | "skip": 0,
7 | "limit": 100,
8 | "items": [
9 | {
10 | "fields": [
11 | {
12 | "name": "such field",
13 | "id": "suchField",
14 | "type": "Symbol"
15 | }
16 | ],
17 | "name": "⚡️ new content type",
18 | "sys": {
19 | "space": {
20 | "sys": {
21 | "type": "Link",
22 | "linkType": "Space",
23 | "id": "emh6o2ireilu"
24 | }
25 | },
26 | "type": "ContentType",
27 | "id": "5kLp8FbRwAG0kcOOYa6GMa",
28 | "revision": 1,
29 | "createdAt": "2014-04-11T08:39:04.421Z",
30 | "updatedAt": "2014-04-11T08:39:04.421Z"
31 | },
32 | "displayField": "suchField"
33 | }
34 | ]
35 | }
36 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/CDAResponse.m:
--------------------------------------------------------------------------------
1 | //
2 | // CDAResponse.m
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 04/03/14.
6 | //
7 | //
8 |
9 | #import "CDAResponse+Private.h"
10 | #import "CDAUtilities.h"
11 |
12 | @implementation CDAResponse
13 |
14 | +(instancetype)responseWithHTTPURLResponse:(NSHTTPURLResponse*)response {
15 | return [[[self class] alloc] initWithHTTPURLResponse:response];
16 | }
17 |
18 | #pragma mark -
19 |
20 | -(instancetype)initWithHTTPURLResponse:(NSHTTPURLResponse*)response {
21 | NSURL* responseURL = response.URL ?: [NSURL URLWithString:@"http://example.com/"];
22 | NSParameterAssert(responseURL);
23 |
24 | self = [super initWithURL:responseURL
25 | statusCode:response.statusCode
26 | HTTPVersion:@"HTTP/1.1"
27 | headerFields:response.allHeaderFields];
28 | return self;
29 | }
30 |
31 | @end
32 |
--------------------------------------------------------------------------------
/Tests/Data/ComplexSyncTests/LinkTestResolve.json:
--------------------------------------------------------------------------------
1 | {
2 | "sys": {
3 | "type": "Array"
4 | },
5 | "total": 1,
6 | "skip": 0,
7 | "limit": 100,
8 | "items": [
9 | {
10 | "sys": {
11 | "space": {
12 | "sys": {
13 | "type": "Link",
14 | "linkType": "Space",
15 | "id": "emh6o2ireilu"
16 | }
17 | },
18 | "type": "Entry",
19 | "contentType": {
20 | "sys": {
21 | "type": "Link",
22 | "linkType": "ContentType",
23 | "id": "51LZmvenywOe8aig28sCgY"
24 | }
25 | },
26 | "id": "6nRlw4CofeeICEYgIqaIIg",
27 | "revision": 1,
28 | "createdAt": "2014-04-09T11:48:42.407Z",
29 | "updatedAt": "2014-04-09T11:48:42.407Z",
30 | "locale": "en-US"
31 | },
32 | "fields": {
33 | "name": "foobar"
34 | }
35 | }
36 | ],
37 | "includes": {}
38 | }
39 |
--------------------------------------------------------------------------------
/Tests/Data/ComplexSyncTests/AssetTestResolve2.json:
--------------------------------------------------------------------------------
1 | {
2 | "sys": {
3 | "type": "Array"
4 | },
5 | "total": 1,
6 | "skip": 0,
7 | "limit": 100,
8 | "items": [
9 | {
10 | "sys": {
11 | "space": {
12 | "sys": {
13 | "type": "Link",
14 | "linkType": "Space",
15 | "id": "emh6o2ireilu"
16 | }
17 | },
18 | "type": "Entry",
19 | "contentType": {
20 | "sys": {
21 | "type": "Link",
22 | "linkType": "ContentType",
23 | "id": "51LZmvenywOe8aig28sCgY"
24 | }
25 | },
26 | "id": "6nRlw4CofeeICEYgIqaIIg",
27 | "revision": 1,
28 | "createdAt": "2014-04-09T11:48:42.407Z",
29 | "updatedAt": "2014-04-09T11:48:42.407Z",
30 | "locale": "en-US"
31 | },
32 | "fields": {
33 | "name": "foobar"
34 | }
35 | }
36 | ],
37 | "includes": {}
38 | }
39 |
--------------------------------------------------------------------------------
/Tests/Data/SyncTests/content-types-for-empty.json:
--------------------------------------------------------------------------------
1 | {
2 | "sys": {
3 | "type": "Array"
4 | },
5 | "total": 1,
6 | "skip": 0,
7 | "limit": 1,
8 | "items": [
9 | {
10 | "sys": {
11 | "space": {
12 | "sys": {
13 | "type": "Link",
14 | "linkType": "Space",
15 | "id": "a7uc4j82xa5d"
16 | }
17 | },
18 | "id": "test",
19 | "type": "ContentType",
20 | "createdAt": "2016-05-11T15:15:36.054Z",
21 | "updatedAt": "2016-05-11T15:15:36.054Z",
22 | "revision": 1
23 | },
24 | "displayField": "test",
25 | "name": "test",
26 | "description": "",
27 | "fields": [
28 | {
29 | "id": "test",
30 | "name": "test",
31 | "type": "Symbol",
32 | "localized": false,
33 | "required": false,
34 | "disabled": false
35 | }
36 | ]
37 | }
38 | ]
39 | }
40 |
--------------------------------------------------------------------------------
/Tests/Data/ComplexSyncTests/NewEntryAndDeletionResolve2.json:
--------------------------------------------------------------------------------
1 | {
2 | "sys": {
3 | "type": "Array"
4 | },
5 | "total": 1,
6 | "skip": 0,
7 | "limit": 100,
8 | "items": [
9 | {
10 | "sys": {
11 | "space": {
12 | "sys": {
13 | "type": "Link",
14 | "linkType": "Space",
15 | "id": "emh6o2ireilu"
16 | }
17 | },
18 | "type": "Entry",
19 | "contentType": {
20 | "sys": {
21 | "type": "Link",
22 | "linkType": "ContentType",
23 | "id": "51LZmvenywOe8aig28sCgY"
24 | }
25 | },
26 | "id": "6nRlw4CofeeICEYgIqaIIg",
27 | "revision": 1,
28 | "createdAt": "2014-04-09T11:48:42.407Z",
29 | "updatedAt": "2014-04-09T11:48:42.407Z",
30 | "locale": "en-US"
31 | },
32 | "fields": {
33 | "name": "foobar"
34 | }
35 | }
36 | ],
37 | "includes": {}
38 | }
39 |
--------------------------------------------------------------------------------
/Tests/SyncBaseTestCase.h:
--------------------------------------------------------------------------------
1 | //
2 | // SyncBaseTestCase.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 09/04/14.
6 | //
7 | //
8 |
9 | #import "ContentfulBaseTestCase.h"
10 |
11 | @interface SyncBaseTestCase : ContentfulBaseTestCase
12 |
13 | @property (nonatomic, readonly) BOOL contentTypesWereFetched;
14 | @property (nonatomic) BOOL expectFieldsInDeletedResources;
15 | @property (nonatomic, readonly) NSUInteger numberOfAssetsCreated;
16 | @property (nonatomic, readonly) NSUInteger numberOfEntriesCreated;
17 | @property (nonatomic, readonly) NSUInteger numberOfAssetsDeleted;
18 | @property (nonatomic, readonly) NSUInteger numberOfEntriesDeleted;
19 | @property (nonatomic, readonly) NSUInteger numberOfAssetsUpdated;
20 | @property (nonatomic, readonly) NSUInteger numberOfEntriesUpdated;
21 |
22 | -(void)addDummyContentType;
23 | -(CDAClient*)buildClient;
24 | -(CDAClient*)mockContentTypeRetrievalForClient:(CDAClient*)client;
25 |
26 | @end
27 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/CDAUtilities.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDAUtilities.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 04/03/14.
6 | //
7 | //
8 |
9 | @import Foundation;
10 |
11 | #import "CDAClient.h"
12 |
13 | @class CDAResource;
14 |
15 | NSString* CDACacheDirectory(void);
16 | NSString* CDACacheFileNameForQuery(CDAClient* client, CDAResourceType resourceType, NSDictionary* query);
17 | NSString* CDACacheFileNameForResource(CDAResource* resource);
18 | NSArray* CDAClassGetSubclasses(Class parentClass);
19 | BOOL CDAClassIsOfType(Class someClass, Class otherClass);
20 | void CDADecodeObjectWithCoder(id object, NSCoder* aDecoder);
21 | void CDAEncodeObjectWithCoder(id object, NSCoder* aCoder);
22 | BOOL CDAIsNoNetworkError(NSError* error);
23 | id CDAReadItemFromFileURL(NSURL* fileURL, CDAClient* client);
24 | NSString* CDASquashCharactersFromSetInString(NSCharacterSet* characterSet, NSString* string);
25 | NSString* CDAValueForQueryParameter(NSURL* url, NSString* queryParameter);
26 |
--------------------------------------------------------------------------------
/Tests/FakeNavigationController.m:
--------------------------------------------------------------------------------
1 | //
2 | // FakeNavigationController.m
3 | // ContentfulSDK
4 | //
5 | // Created by JP Wright on 13/01/2017.
6 | //
7 | //
8 |
9 | #import "FakeNavigationController.h"
10 |
11 | @interface FakeNavigationController ()
12 |
13 | @end
14 |
15 | @implementation FakeNavigationController
16 |
17 | - (void)viewDidLoad {
18 | [super viewDidLoad];
19 | // Do any additional setup after loading the view.
20 | }
21 |
22 | - (void)didReceiveMemoryWarning {
23 | [super didReceiveMemoryWarning];
24 | // Dispose of any resources that can be recreated.
25 | }
26 |
27 | /*
28 | #pragma mark - Navigation
29 |
30 | // In a storyboard-based application, you will often want to do a little preparation before navigation
31 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
32 | // Get the new view controller using [segue destinationViewController].
33 | // Pass the selected object to the new view controller.
34 | }
35 | */
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/Tests/Data/SyncTests/update-for-empty.json:
--------------------------------------------------------------------------------
1 | {
2 | "sys": {
3 | "type": "Array"
4 | },
5 | "items": [
6 | {
7 | "sys": {
8 | "space": {
9 | "sys": {
10 | "type": "Link",
11 | "linkType": "Space",
12 | "id": "a7uc4j82xa5d"
13 | }
14 | },
15 | "id": "3f5qqrqbsAGMqAeIkkMYeK",
16 | "type": "Entry",
17 | "createdAt": "2016-05-11T15:15:46.680Z",
18 | "updatedAt": "2016-05-11T15:17:12.148Z",
19 | "revision": 2,
20 | "contentType": {
21 | "sys": {
22 | "type": "Link",
23 | "linkType": "ContentType",
24 | "id": "test"
25 | }
26 | }
27 | },
28 | "fields": {
29 | "test": {
30 | "en-US": null
31 | }
32 | }
33 | }
34 | ],
35 | "nextSyncUrl": "https://cdn.contentful.com/spaces/a7uc4j82xa5d/sync?sync_token=w5ZGw6JFwqZmVcKsE8Kow4grw45QdybDiMOEwoFaGsOjw7_DvwQdCmZXwqnChsOcAcOkUysgwrTCsy4bw6jCkcO9wqchwoFvwppIGWxiwp7ClwfCmQfDunpyUy1KOEptd8Oyf2rCn0TDvcO6LXbDhEEG"
36 | }
37 |
--------------------------------------------------------------------------------
/Tests/Data/SyncTests/initial-for-empty.json:
--------------------------------------------------------------------------------
1 | {
2 | "sys": {
3 | "type": "Array"
4 | },
5 | "items": [
6 | {
7 | "sys": {
8 | "space": {
9 | "sys": {
10 | "type": "Link",
11 | "linkType": "Space",
12 | "id": "a7uc4j82xa5d"
13 | }
14 | },
15 | "id": "3f5qqrqbsAGMqAeIkkMYeK",
16 | "type": "Entry",
17 | "createdAt": "2016-05-11T15:15:46.680Z",
18 | "updatedAt": "2016-05-11T15:15:46.680Z",
19 | "revision": 1,
20 | "contentType": {
21 | "sys": {
22 | "type": "Link",
23 | "linkType": "ContentType",
24 | "id": "test"
25 | }
26 | }
27 | },
28 | "fields": {
29 | "test": {
30 | "en-US": "yolo"
31 | }
32 | }
33 | }
34 | ],
35 | "nextSyncUrl": "https://cdn.contentful.com/spaces/a7uc4j82xa5d/sync?sync_token=w5ZGw6JFwqZmVcKsE8Kow4grw45QdyY9ZMK9AsOcwqzCqmEWwr7CucOhw7LCm8ONZQICw4PCo8Olwq0lwofCocO2C3rDmAM_wr_DuMOcDBVGwqnCpcOBXsKXw6M9J8O4w4EUw7Zww6TCtsKwOzfCucOpVkLDtWXCsMOydg"
36 | }
37 |
--------------------------------------------------------------------------------
/Tests/Data/ComplexSyncTests/AddContentTypesUpdate.json:
--------------------------------------------------------------------------------
1 | {
2 | "sys": {
3 | "type": "Array"
4 | },
5 | "items": [
6 | {
7 | "sys": {
8 | "space": {
9 | "sys": {
10 | "type": "Link",
11 | "linkType": "Space",
12 | "id": "emh6o2ireilu"
13 | }
14 | },
15 | "type": "Entry",
16 | "contentType": {
17 | "sys": {
18 | "type": "Link",
19 | "linkType": "ContentType",
20 | "id": "5kLp8FbRwAG0kcOOYa6GMa"
21 | }
22 | },
23 | "id": "7FQCYfimc0aQa8okuCakAS",
24 | "revision": 1,
25 | "createdAt": "2014-04-11T08:39:23.206Z",
26 | "updatedAt": "2014-04-11T08:39:23.206Z"
27 | },
28 | "fields": {
29 | "suchField": {
30 | "en-US": "new entry such crash wow"
31 | }
32 | }
33 | }
34 | ],
35 | "nextSyncUrl": "https://cdn.contentful.com/spaces/emh6o2ireilu/sync?sync_token=w5ZGw6JFwqZmVcKsE8Kow4grw45QdyZhfMOjXcKJw54MwqHChsKFYwhawqzDui4qwrfClCzCoHcuwrEFHsO_X1UFZMOpw7DCoUY0w4sMw6BcbDLDlsKkJ8KTRsK6M8K-eMKGwoPDslnDnDDDrcK0MmoCWMK1"
36 | }
37 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2014 Contentful GmbH - https://www.contentful.com
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/Tests/Data/ComplexSyncTests/AssetTestResolve.json:
--------------------------------------------------------------------------------
1 | {
2 | "sys": {
3 | "type": "Array"
4 | },
5 | "total": 1,
6 | "skip": 0,
7 | "limit": 100,
8 | "items": [
9 | {
10 | "fields": {
11 | "title": "contentful-logo",
12 | "file": {
13 | "fileName": "512_black.png",
14 | "contentType": "image/png",
15 | "details": {
16 | "image": {
17 | "width": 512,
18 | "height": 512
19 | },
20 | "size": 4189
21 | },
22 | "url": "//images.contentful.com/emh6o2ireilu/2q1Ns7Oygo2mAgoweuMCAA/7a4eb574952f359b851b3f353573b708/512_black.png"
23 | }
24 | },
25 | "sys": {
26 | "space": {
27 | "sys": {
28 | "type": "Link",
29 | "linkType": "Space",
30 | "id": "emh6o2ireilu"
31 | }
32 | },
33 | "type": "Asset",
34 | "id": "2q1Ns7Oygo2mAgoweuMCAA",
35 | "revision": 2,
36 | "createdAt": "2014-03-25T11:01:41.057Z",
37 | "updatedAt": "2014-04-10T08:46:27.961Z",
38 | "locale": "en-US"
39 | }
40 | }
41 | ]
42 | }
43 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/CDALocalizablePersistedEntry.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDALocalizablePersistedEntry.h
3 | //
4 | //
5 | // Created by Boris Bügling on 23/09/15.
6 | //
7 | //
8 |
9 | #if __has_feature(modules)
10 | @import CoreData;
11 | #else
12 | #import
13 | #endif
14 |
15 | #import "CDALocalizedPersistedEntry.h"
16 |
17 | /**
18 | * Any class representing a set of localizable persisted entries should inherit from this class.
19 | */
20 | @interface CDALocalizablePersistedEntry : NSManagedObject
21 |
22 | /** Set of localized entries of type `CDALocalizedPersistedEntry` */
23 | @property (nonatomic) NSSet* localizedEntries;
24 |
25 | @end
26 |
27 | #pragma mark -
28 |
29 | @interface CDALocalizablePersistedEntry (Additions)
30 |
31 | /**
32 | Add a localized entry to the collection.
33 |
34 | @param entry The entry to add to the collection.
35 | */
36 | - (void)addLocalizedEntriesObject:(id)entry;
37 |
38 | /**
39 | Remove a localized entry to the collection.
40 |
41 | @param entry The entry to remove from the collection.
42 | */
43 | - (void)removeLocalizedEntriesObject:(id)entry;
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/Tests/Data/ComplexSyncTests/NewEntryAndDeletionResolve.json:
--------------------------------------------------------------------------------
1 | {
2 | "sys": {
3 | "type": "Array"
4 | },
5 | "total": 1,
6 | "skip": 0,
7 | "limit": 100,
8 | "items": [
9 | {
10 | "fields": {
11 | "title": "contentful-logo",
12 | "file": {
13 | "fileName": "512_black.png",
14 | "contentType": "image/png",
15 | "details": {
16 | "image": {
17 | "width": 512,
18 | "height": 512
19 | },
20 | "size": 4189
21 | },
22 | "url": "//images.contentful.com/emh6o2ireilu/2q1Ns7Oygo2mAgoweuMCAA/7a4eb574952f359b851b3f353573b708/512_black.png"
23 | }
24 | },
25 | "sys": {
26 | "space": {
27 | "sys": {
28 | "type": "Link",
29 | "linkType": "Space",
30 | "id": "emh6o2ireilu"
31 | }
32 | },
33 | "type": "Asset",
34 | "id": "2q1Ns7Oygo2mAgoweuMCAA",
35 | "revision": 2,
36 | "createdAt": "2014-03-25T11:01:41.057Z",
37 | "updatedAt": "2014-04-10T08:46:27.961Z",
38 | "locale": "en-US"
39 | }
40 | }
41 | ]
42 | }
43 |
--------------------------------------------------------------------------------
/Tests/Data/SyncTests/added.json:
--------------------------------------------------------------------------------
1 | {
2 | "sys": {
3 | "type": "Array"
4 | },
5 | "items": [
6 | {
7 | "sys": {
8 | "space": {
9 | "sys": {
10 | "type": "Link",
11 | "linkType": "Space",
12 | "id": "emh6o2ireilu"
13 | }
14 | },
15 | "type": "Entry",
16 | "contentType": {
17 | "sys": {
18 | "type": "Link",
19 | "linkType": "ContentType",
20 | "id": "6bAvxqodl6s4MoKuWYkmqe"
21 | }
22 | },
23 | "id": "1gQ4P2tG7QaGkQwkC4a6Gg",
24 | "revision": 1,
25 | "createdAt": "2014-03-25T11:04:03.822Z",
26 | "updatedAt": "2014-03-25T11:04:03.822Z"
27 | },
28 | "fields": {
29 | "title": {
30 | "en-US": "Second entry"
31 | },
32 | "body": {
33 | "en-US": "some text"
34 | }
35 | }
36 | }
37 | ],
38 | "nextSyncUrl": "https://cdn.contentful.com/spaces/emh6o2ireilu/sync?sync_token=w5ZGw6JFwqZmVcKsE8Kow4grw45QdyY0w4bCiMKOWDIFw61bwqQ_w73CnMKsB8KpwrFZPsOZw5ZQwqDDnUA0w5tOPRtwwoAkwpJMTzghdEnDjCkiw5fCuynDlsO5DyvCsjgQa2TDisKNZ8Kqw4TCjhZIGQ"
39 | }
40 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/CDAConfiguration.m:
--------------------------------------------------------------------------------
1 | //
2 | // CDAConfiguration.m
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 04/03/14.
6 | //
7 | //
8 |
9 | #import "CDAConfiguration+Private.h"
10 |
11 | NSString* const CDA_DEFAULT_SERVER = @"cdn.contentful.com";
12 | static NSString* const CDA_PREVIEW_SERVER = @"preview.contentful.com";
13 |
14 | @interface CDAConfiguration ()
15 |
16 | @property (nonatomic) BOOL usesManagementAPI;
17 |
18 | @end
19 |
20 | #pragma mark -
21 |
22 | @implementation CDAConfiguration
23 |
24 | +(instancetype)defaultConfiguration {
25 | CDAConfiguration* configuration = [CDAConfiguration new];
26 | configuration.filterNonExistingResources = NO;
27 | configuration.previewMode = NO;
28 | configuration.rateLimiting = NO;
29 | configuration.secure = YES;
30 | configuration.server = CDA_DEFAULT_SERVER;
31 | return configuration;
32 | }
33 |
34 | #pragma mark -
35 |
36 | -(void)setPreviewMode:(BOOL)previewMode {
37 | if (_previewMode == previewMode) {
38 | return;
39 | }
40 |
41 | _previewMode = previewMode;
42 |
43 | if (previewMode) {
44 | self.server = CDA_PREVIEW_SERVER;
45 | }
46 | }
47 |
48 | @end
49 |
--------------------------------------------------------------------------------
/Podfile:
--------------------------------------------------------------------------------
1 | #!/usr/bin/ruby
2 |
3 | source 'https://github.com/CocoaPods/Specs.git'
4 | source 'https://github.com/contentful/CocoaPodsSpecs.git'
5 |
6 | ## iOS
7 | target 'ContentfulDeliveryAPI' do
8 | podspec :path => 'ContentfulDeliveryAPI.podspec'
9 | platform :ios, "9.3"
10 | end
11 |
12 | ## tvOS
13 | target 'ContentfulDeliveryAPI_tvOS' do
14 | podspec :path => 'ContentfulDeliveryAPI.podspec'
15 | platform :tvos, "9.2"
16 | end
17 |
18 | target 'ContentfulDeliveryAPI_macOS' do
19 | podspec :path => 'ContentfulDeliveryAPI.podspec'
20 | platform :osx, "10.12"
21 | end
22 |
23 |
24 | # Cocoapods docs are wrong and don't work for
25 | target 'DeliveryTests' do
26 | platform :ios, "9.3"
27 |
28 | pod 'CCLRequestReplay', :git => 'https://github.com/neonichu/CCLRequestReplay.git'
29 | pod 'OCMock', :inhibit_warnings => true
30 | pod 'VCRURLConnection', '= 0.2.4', :inhibit_warnings => true
31 | pod 'FBSnapshotTestCase/Core', :inhibit_warnings => true
32 | end
33 |
34 |
35 |
36 |
37 | ## Post install
38 | post_install do |installer|
39 |
40 | installer.pods_project.targets.each do |target|
41 | target.build_configurations.each do |config|
42 | config.build_settings['ONLY_ACTIVE_ARCH'] = "NO"
43 | end
44 | end
45 | end
46 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/Resources/CDAArray.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDAArray.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 04/03/14.
6 | //
7 | //
8 |
9 | #import "CDANullabilityStubs.h"
10 | #import "CDAResource.h"
11 |
12 | /**
13 | A list of resources which was retrieved from the server.
14 | */
15 | @interface CDAArray : CDAResource
16 |
17 | /** @name Accessing Local Data */
18 |
19 | /** A list of items available locally. */
20 | @property (nonatomic, readonly) NSArray* __nonnull items;
21 |
22 | /** @name Information about Remote Data */
23 |
24 | /** The maximum number of resources available in items. */
25 | @property (nonatomic, readonly) NSUInteger limit;
26 | /** The offset of items in terms of all data available on the server. */
27 | @property (nonatomic, readonly) NSUInteger skip;
28 | /** The total number of resources which are available on the server. */
29 | @property (nonatomic, readonly) NSUInteger total;
30 |
31 | /** @name Errors in Remote Data */
32 |
33 | /**
34 | * An array of non-fatal errors encountered while fetching the receiver.
35 | *
36 | * For example, if there is a link to an Entry which no longer exists, there will be a `notResolvable`
37 | * error in the `errors` array.
38 | */
39 | @property (nonatomic, readonly) NSArray* __nonnull errors;
40 |
41 | @end
42 |
--------------------------------------------------------------------------------
/Tests/ContentfulBaseTestCase.h:
--------------------------------------------------------------------------------
1 | //
2 | // ContentfulBaseTestCase.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 06/03/14.
6 | //
7 | //
8 |
9 | @import XCTest;
10 |
11 | #import
12 | #import
13 |
14 | @interface ContentfulBaseTestCase : XCTestCase
15 |
16 | @property (nonatomic) CDAClient* client;
17 |
18 | - (void)addRecordingWithJSONNamed:(NSString*)JSONName
19 | inDirectory:(NSString*)directory
20 | matcher:(CCLURLRequestMatcher)matcher;
21 | - (void)addResponseWithData:(NSData*)data
22 | statusCode:(NSInteger)statusCode
23 | headers:(NSDictionary*)headers
24 | matcher:(CCLURLRequestMatcher)matcher;
25 | - (void)addResponseWithError:(NSError*)error matcher:(CCLURLRequestMatcher)matcher;
26 | - (void)assertField:(CDAField*)field
27 | hasIdentifier:(NSString*)identifier
28 | name:(NSString*)name
29 | type:(CDAFieldType)type;
30 | - (CDAEntry*)customEntryHelperWithFields:(NSDictionary*)fields;
31 | - (void)removeAllStubs;
32 | - (void)setUpCCLRequestReplayForNSURLSession;
33 | - (void)stubHTTPRequestUsingFixtures:(NSDictionary*)fixtureMap inDirectory:(NSString*)directoryName;
34 |
35 | @end
36 |
--------------------------------------------------------------------------------
/Tests/Data/SyncTests/added-asset.json:
--------------------------------------------------------------------------------
1 | {
2 | "sys": {
3 | "type": "Array"
4 | },
5 | "items": [
6 | {
7 | "fields": {
8 | "title": {
9 | "en-US": "doge"
10 | },
11 | "file": {
12 | "en-US": {
13 | "fileName": "vaa4by0.png",
14 | "contentType": "image/png",
15 | "details": {
16 | "image": {
17 | "width": 265,
18 | "height": 265
19 | },
20 | "size": 103652
21 | },
22 | "url": "//images.contentful.com/emh6o2ireilu/6koKmTXVzUquae6ewQQ8Eu/5f79cef98e3feb466c30f0b38bec0359/vaa4by0.png"
23 | }
24 | }
25 | },
26 | "sys": {
27 | "space": {
28 | "sys": {
29 | "type": "Link",
30 | "linkType": "Space",
31 | "id": "emh6o2ireilu"
32 | }
33 | },
34 | "type": "Asset",
35 | "id": "6koKmTXVzUquae6ewQQ8Eu",
36 | "revision": 1,
37 | "createdAt": "2014-03-25T11:08:25.412Z",
38 | "updatedAt": "2014-03-25T11:08:25.412Z"
39 | }
40 | }
41 | ],
42 | "nextSyncUrl": "https://cdn.contentful.com/spaces/emh6o2ireilu/sync?sync_token=w5ZGw6JFwqZmVcKsE8Kow4grw45QdyZ_NnHDoQzCtcKoMh9KZHtAWcObw7XCimZgVGPChUfDuxQHwoHDosO6CcKodsO2MWJQwrrCrsOswpl5w6LCuV0tw4Njwo9Ww5fCl8KqEgB6XgAJNVF2wpk3Lg"
43 | }
44 |
--------------------------------------------------------------------------------
/Tests/RobustnessTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // RobustnessTests.m
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 31/10/14.
6 | //
7 | //
8 |
9 | #import "CDAClient+Private.h"
10 | #import "CDAContentTypeRegistry.h"
11 | #import "CDAResponseSerializer.h"
12 | #import "CDAResource+Private.h"
13 | #import "ContentfulBaseTestCase.h"
14 |
15 | @interface RobustnessTests : ContentfulBaseTestCase
16 |
17 | @end
18 |
19 | #pragma mark -
20 |
21 | @implementation RobustnessTests
22 |
23 | -(void)testCrash001 {
24 | CDAResponseSerializer* serializer = [[CDAResponseSerializer alloc] initWithClient:self.client];
25 | NSError* error;
26 |
27 | NSData* jsonData = [NSData dataWithContentsOfURL:[[NSBundle bundleForClass:self.class] URLForResource:@"ContentType-001" withExtension:@"json" subdirectory:@"Fixtures"]];
28 | XCTAssertNotNil(jsonData);
29 |
30 | CDAContentType* contentType = [serializer responseObjectForResponse:nil data:jsonData error:&error];
31 | XCTAssertNotNil(contentType);
32 | [self.client.contentTypeRegistry addContentType:contentType];
33 |
34 | jsonData = [NSData dataWithContentsOfURL:[[NSBundle bundleForClass:self.class] URLForResource:@"Crash-001" withExtension:@"json" subdirectory:@"Fixtures"]];
35 | XCTAssertNotNil(jsonData);
36 |
37 | CDAEntry* entry = [serializer responseObjectForResponse:nil data:jsonData error:&error];
38 | XCTAssertNotNil(entry);
39 | }
40 |
41 | @end
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: objective-c
2 | git:
3 | depth: 50
4 | submodules: false
5 | osx_image: xcode9.3
6 | rvm:
7 | - 2.4.1
8 | before_install:
9 | - bundle install
10 | - bundle exec pod repo update --silent
11 | install:
12 | - bundle exec pod install
13 | script:
14 | - "./scripts/travis-build-test.sh"
15 | after_success:
16 | - bundle exec pod lib lint ContentfulDeliveryAPI.podspec --allow-warnings
17 | notifications:
18 | slack:
19 | - secure: pbLVGeA+577zmld+ie/1KUWxin8PFB+uXogz1zrVhEqnparjbHNMvFfaAGG1gbaAJC0skGksCe+LeBrhLargbLSgAT3HrObwDCIu7H8IjaYOEhpNTHCObrwRIyOeBVHHAhjgjeElM7hvptJjRMuERErcnL65EOlaIdm4ZqOg3/0=
20 | env:
21 | global:
22 | - IOS_SDK=iphonesimulator IOS_VERSION=11.3 DEVICE_NAME='iPhone 6s'
23 | - secure: n/hnbmOoeLt4g+Mzm6Nm/fnxwr7fFjfFTlNxEco7kk9oeNklj0vudOwbYtxL2AWuMNWX/tSHlUieKf4UGOiwzFeQmWyLdi0dkwSKRMNBNz2XQrlzjemZNf8V9+E6+JPeH8BVBKyscYgNevrp7R0Lx2h5mcDVogHm416yUiNzGOQ=
24 | - secure: FAIgFb/XlYTHWXAE7dzl5KFAMmST39forxsfmJdysXdaIUXK1Y44PJnS4HQ0cRa79e+o+NSOJSHLGI+qboXNoDAHqaDGBqtC7QROjW7ed0ZQp0iyNeebSq8TQzuOwdrqEjh9SGK24bgbTgQx+i8brYRJA+N8igfNtVoTUXj7buI=
25 | - secure: LyiQhHG89Zn0FdprFntjvT34DOcvFU/IITWhhowfgYrXGObUTEOyIyE3ve6fJpMm23B8/u1EUNxBVvqxevdGmA2RuoJiMMy+V/uFsBHmuOeJ8TeDYOgjyWJgsJt1bfDLpFwX2Ztu0smdMeuBpmsOA2I3FW0mDCx5tiAuScNidnE=
26 | - secure: L0njJqmusJJZPCWwMUTvb1vMJP3r4rNpLgDcWW1XtdZyNHE/F4CFzbawX/ve2ApzMXRV69XBIGLmBfl3hW0XCwyHR9nCe3u8/MRSZxapSNuArSjodHrPrddUGtAsgjKfKw1DlzNGByg2LpXLnfEBLnJYcYCosza3TI52JNcEv3c=
27 |
28 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/CDAInputSanitizer.m:
--------------------------------------------------------------------------------
1 | //
2 | // CDAInputSanitizer.m
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 09/05/14.
6 | //
7 | //
8 |
9 | #import "CDAInputSanitizer.h"
10 |
11 | @implementation CDAInputSanitizer
12 |
13 | +(NSArray*)sanitizeArray:(NSArray*)array {
14 | NSMutableArray* result = [array mutableCopy];
15 |
16 | [result removeObject:[NSNull null]];
17 |
18 | [array enumerateObjectsUsingBlock:^(id value, NSUInteger idx, BOOL *stop) {
19 | [result replaceObjectAtIndex:idx withObject:[self sanitizeObject:value]];
20 | }];
21 |
22 | return [result copy];
23 | }
24 |
25 | +(NSDictionary*)sanitizeDictionary:(NSDictionary*)dictionary {
26 | NSMutableDictionary* result = [dictionary mutableCopy];
27 |
28 | for (id key in dictionary.allKeys) {
29 | id value = result[key];
30 |
31 | if (value == [NSNull null]) {
32 | [result removeObjectForKey:key];
33 | } else {
34 | result[key] = [self sanitizeObject:value];
35 | }
36 | }
37 |
38 | return [result copy];
39 | }
40 |
41 | +(id)sanitizeObject:(id)object {
42 | if ([object isKindOfClass:[NSArray class]]) {
43 | return [self sanitizeArray:object];
44 | }
45 |
46 | if ([object isKindOfClass:[NSDictionary class]]) {
47 | return [self sanitizeDictionary:object];
48 | }
49 |
50 | return object;
51 | }
52 |
53 | @end
54 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/CDAPersistedAsset.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDAPersistedAsset.h
3 | // ContentfulSDK
4 | //
5 | // Created by JP Wright on 11.05.17.
6 | //
7 | //
8 |
9 | #ifndef CDAPersistedAsset_h
10 | #define CDAPersistedAsset_h
11 |
12 | #if __has_feature(modules)
13 | @import Foundation;
14 | #else
15 | #import
16 | #endif
17 |
18 | /**
19 | * Any class representing Assets saved to a persistent store needs to conform to this protocol.
20 | *
21 | * If any of the optional properties are implemented, they will automatically be mapped to the
22 | * corresponding Asset fields from Contentful.
23 | */
24 | @protocol CDAPersistedAsset
25 |
26 | /** The `sys.id` of the Asset. */
27 | @property (nonatomic, nonnull) NSString* identifier;
28 | /** File type of the Asset. */
29 | @property (nonatomic, nullable) NSString* internetMediaType;
30 | /** URL for the underlying file represented by the Asset. */
31 | @property (nonatomic, nullable) NSString* url;
32 |
33 | @optional
34 |
35 | /** The description of the Asset. */
36 | @property (nonatomic, nullable) NSString* assetDescription;
37 | /** The title of the Asset. */
38 | @property (nonatomic, nullable) NSString* title;
39 | /** The width of the Asset, if it is an image. */
40 | @property (nonatomic, nullable) NSNumber* width;
41 | /** The height of the Asset, if it is an image. */
42 | @property (nonatomic, nullable) NSNumber* height;
43 |
44 | @end
45 |
46 | #endif /* CDAPersistedAsset_h */
47 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/Resources/CDAContentType.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDAContentType.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 04/03/14.
6 | //
7 | //
8 |
9 | #import "CDANullabilityStubs.h"
10 | #import "CDAResource.h"
11 |
12 | @class CDAField;
13 |
14 | NS_ASSUME_NONNULL_BEGIN
15 |
16 | /**
17 | Content Types are schemas describing the shape of Entries. They mainly consist of a list of fields
18 | acting as a blueprint for Entries.
19 |
20 | Note: They're not related to the HTTP Content-Type header.
21 | */
22 | @interface CDAContentType : CDAResource
23 |
24 | /** @name Accessing Fields */
25 |
26 | /** List of all fields as an array of `CDAField` objects. */
27 | @property (nonatomic, readonly) NSArray* fields;
28 |
29 | /**
30 | Retrieve a specific field by its identifier.
31 |
32 | @param identifier The `sys.id` to look for in the list of fields.
33 | @return The specific field requested, or `nil` if none matches.
34 | */
35 | -(CDAField* __nullable)fieldForIdentifier:(NSString*)identifier;
36 |
37 | /** @name Accessing Meta-Data */
38 |
39 | /** The identifier of the Field which should be displayed as a title for Entries */
40 | @property (nonatomic, readonly) NSString* __nullable displayField;
41 | /** Name of the Content Type. */
42 | @property (nonatomic, readonly) NSString* name;
43 | /** Description of the Content Type. */
44 | @property (nonatomic, readonly) NSString* __nullable userDescription;
45 |
46 | @end
47 |
48 | NS_ASSUME_NONNULL_END
49 |
--------------------------------------------------------------------------------
/Tests/Data/Recordings/ComplexSyncTests.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "body" : "ewogICJzeXMiOiB7CiAgICAidHlwZSI6ICJFcnJvciIsCiAgICAiaWQiOiAiQWNj\r\nZXNzVG9rZW5JbnZhbGlkIgogIH0sCiAgIm1lc3NhZ2UiOiAiVGhlIGFjY2VzcyB0\r\nb2tlbiB5b3Ugc2VudCBjb3VsZCBub3QgYmUgZm91bmQgb3IgaXMgaW52YWxpZC4i\r\nLAogICJyZXF1ZXN0SWQiOiAiOTBhLTIxMzA4NzIxODQiCn0K",
4 | "headers" : {
5 | "Date" : "Thu, 24 Sep 2015 20:03:43 GMT",
6 | "X-Served-By" : "cache-fra1227-FRA",
7 | "Access-Control-Allow-Origin" : "*",
8 | "Via" : "1.1 varnish",
9 | "Accept-Ranges" : "bytes",
10 | "Content-Type" : "application\/vnd.contentful.delivery.v1+json",
11 | "Access-Control-Allow-Headers" : "Accept,Accept-Language,Authorization,Cache-Control,Content-Length,Content-Range,Content-Type,DNT,Destination,Expires,If-Match,If-Modified-Since,If-None-Match,Keep-Alive,Last-Modified,Origin,Pragma,Range,User-Agent,X-Http-Method-Override,X-Mx-ReqToken,X-Requested-With,X-Contentful-Version,X-Contentful-Content-Type,X-Contentful-Organization,X-Contentful-Skip-Transformation",
12 | "Connection" : "keep-alive",
13 | "Access-Control-Max-Age" : "86400",
14 | "Server" : "nginx",
15 | "X-Cache" : "MISS",
16 | "X-Cache-Hits" : "0",
17 | "Content-Length" : "180",
18 | "Access-Control-Allow-Methods" : "GET,HEAD,OPTIONS",
19 | "Cache-Control" : "max-age=0"
20 | },
21 | "method" : "GET",
22 | "status" : 401,
23 | "uri" : "https:\/\/cdn.contentful.com\/spaces\/test\/"
24 | }
25 | ]
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/CDARequest.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDARequest.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 10/03/14.
6 | //
7 | //
8 |
9 | #if __has_feature(modules)
10 | @import Foundation;
11 | #else
12 | #import
13 | #endif
14 |
15 | #import "CDANullabilityStubs.h"
16 |
17 | /**
18 | A request encapsulates all necessary information for retrieving specific resources.
19 | */
20 | @interface CDARequest : NSOperation
21 |
22 | /** @name Accessing URL Connection Information */
23 |
24 | /** Error which occured during the lifetime of the request, if any. */
25 | @property (readonly, nonatomic) NSError* __nullable error;
26 | /** The actual request being sent to the server. */
27 | @property (readonly, nonatomic) NSURLRequest* __nullable request;
28 | /** The underlying response received from the server. */
29 | @property (readonly, nonatomic) NSHTTPURLResponse* __nullable response;
30 |
31 | /** @name Accessing Response Data */
32 |
33 | /** The raw data received from the server. */
34 | @property (readonly, nonatomic) NSData* __nullable responseData;
35 | /** The processed response data, usually an instance of a `CDAResource` subclass. */
36 | @property (readonly, nonatomic) id __nullable responseObject;
37 | /** String representation of the data received from the server. */
38 | @property (readonly, nonatomic) NSString* __nullable responseString;
39 | /** Encoding used for the response. */
40 | @property (readonly, nonatomic) NSStringEncoding responseStringEncoding;
41 |
42 | @end
43 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/Resources/CDAResource+Private.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDAResource+Private.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 04/03/14.
6 | //
7 | //
8 |
9 | #import "CDAResource.h"
10 |
11 | @class CDAClient;
12 |
13 | @interface CDAResource ()
14 |
15 | @property (nonatomic, weak) CDAClient* client;
16 | @property (nonatomic) NSString* defaultLocaleOfSpace; // FIXME: should this be `readonly`?
17 |
18 | +(NSString*)CDAType;
19 | +(BOOL)classIsOfType:(Class)class;
20 | +(instancetype)resourceObjectForDictionary:(NSDictionary*)dictionary
21 | client:(CDAClient*)client
22 | localizationAvailable:(BOOL)localizationAvailable;
23 |
24 | -(BOOL)createdAfterDate:(NSDate*)date;
25 | -(instancetype)initWithDictionary:(NSDictionary*)dictionary
26 | client:(CDAClient*)client
27 | localizationAvailable:(BOOL)localizationAvailable;
28 | -(NSDictionary*)localizeFieldsFromDictionary:(NSDictionary*)fields;
29 | -(NSDictionary*)localizedDictionaryFromDictionary:(NSDictionary*)dictionary
30 | forLocale:(NSString*)locale
31 | default:(BOOL)isDefault;
32 | -(NSDictionary*)parseDictionary:(NSDictionary*)dictionary;
33 | -(void)resolveLinksWithIncludedAssets:(NSDictionary*)assets entries:(NSDictionary*)entries;
34 | -(BOOL)updatedAfterDate:(NSDate*)date;
35 | -(void)updateWithContentsOfDictionary:(NSDictionary*)dictionary client:(CDAClient*)client;
36 | -(void)updateWithResource:(CDAResource*)resource;
37 |
38 | @end
39 |
--------------------------------------------------------------------------------
/docs/js/jazzy.js:
--------------------------------------------------------------------------------
1 | window.jazzy = {'docset': false}
2 | if (typeof window.dash != 'undefined') {
3 | document.documentElement.className += ' dash'
4 | window.jazzy.docset = true
5 | }
6 | if (navigator.userAgent.match(/xcode/i)) {
7 | document.documentElement.className += ' xcode'
8 | window.jazzy.docset = true
9 | }
10 |
11 | // On doc load, toggle the URL hash discussion if present
12 | $(document).ready(function() {
13 | if (!window.jazzy.docset) {
14 | var linkToHash = $('a[href="' + window.location.hash +'"]');
15 | linkToHash.trigger("click");
16 | }
17 | });
18 |
19 | // On token click, toggle its discussion and animate token.marginLeft
20 | $(".token").click(function(event) {
21 | if (window.jazzy.docset) {
22 | return;
23 | }
24 | var link = $(this);
25 | var animationDuration = 300;
26 | var tokenOffset = "15px";
27 | var original = link.css('marginLeft') == tokenOffset;
28 | link.animate({'margin-left':original ? "0px" : tokenOffset}, animationDuration);
29 | $content = link.parent().parent().next();
30 | $content.slideToggle(animationDuration);
31 |
32 | // Keeps the document from jumping to the hash.
33 | var href = $(this).attr('href');
34 | if (history.pushState) {
35 | history.pushState({}, '', href);
36 | } else {
37 | location.hash = href;
38 | }
39 | event.preventDefault();
40 | });
41 |
42 | // Dumb down quotes within code blocks that delimit strings instead of quotations
43 | // https://github.com/realm/jazzy/issues/714
44 | $("code q").replaceWith(function () {
45 | return ["\"", $(this).contents(), "\""];
46 | });
47 |
--------------------------------------------------------------------------------
/docs/docsets/ContentfulDeliveryAPI.docset/Contents/Resources/Documents/js/jazzy.js:
--------------------------------------------------------------------------------
1 | window.jazzy = {'docset': false}
2 | if (typeof window.dash != 'undefined') {
3 | document.documentElement.className += ' dash'
4 | window.jazzy.docset = true
5 | }
6 | if (navigator.userAgent.match(/xcode/i)) {
7 | document.documentElement.className += ' xcode'
8 | window.jazzy.docset = true
9 | }
10 |
11 | // On doc load, toggle the URL hash discussion if present
12 | $(document).ready(function() {
13 | if (!window.jazzy.docset) {
14 | var linkToHash = $('a[href="' + window.location.hash +'"]');
15 | linkToHash.trigger("click");
16 | }
17 | });
18 |
19 | // On token click, toggle its discussion and animate token.marginLeft
20 | $(".token").click(function(event) {
21 | if (window.jazzy.docset) {
22 | return;
23 | }
24 | var link = $(this);
25 | var animationDuration = 300;
26 | var tokenOffset = "15px";
27 | var original = link.css('marginLeft') == tokenOffset;
28 | link.animate({'margin-left':original ? "0px" : tokenOffset}, animationDuration);
29 | $content = link.parent().parent().next();
30 | $content.slideToggle(animationDuration);
31 |
32 | // Keeps the document from jumping to the hash.
33 | var href = $(this).attr('href');
34 | if (history.pushState) {
35 | history.pushState({}, '', href);
36 | } else {
37 | location.hash = href;
38 | }
39 | event.preventDefault();
40 | });
41 |
42 | // Dumb down quotes within code blocks that delimit strings instead of quotations
43 | // https://github.com/realm/jazzy/issues/714
44 | $("code q").replaceWith(function () {
45 | return ["\"", $(this).contents(), "\""];
46 | });
47 |
--------------------------------------------------------------------------------
/Tests/Data/ComplexSyncTests/AssetTestUpdate.json:
--------------------------------------------------------------------------------
1 | {
2 | "sys": {
3 | "type": "Array"
4 | },
5 | "items": [
6 | {
7 | "sys": {
8 | "space": {
9 | "sys": {
10 | "type": "Link",
11 | "linkType": "Space",
12 | "id": "emh6o2ireilu"
13 | }
14 | },
15 | "type": "Entry",
16 | "contentType": {
17 | "sys": {
18 | "type": "Link",
19 | "linkType": "ContentType",
20 | "id": "6bAvxqodl6s4MoKuWYkmqe"
21 | }
22 | },
23 | "id": "1Wl5HnguK8CiaykiQAiGu6",
24 | "revision": 2,
25 | "createdAt": "2014-04-09T11:48:47.866Z",
26 | "updatedAt": "2014-04-09T13:53:33.420Z"
27 | },
28 | "fields": {
29 | "title": {
30 | "en-US": "WithCategory"
31 | },
32 | "body": {
33 | "en-US": "some text"
34 | },
35 | "category": {
36 | "en-US": {
37 | "sys": {
38 | "type": "Link",
39 | "linkType": "Entry",
40 | "id": "6nRlw4CofeeICEYgIqaIIg"
41 | }
42 | }
43 | },
44 | "picture": {
45 | "en-US": {
46 | "sys": {
47 | "type": "Link",
48 | "linkType": "Asset",
49 | "id": "2q1Ns7Oygo2mAgoweuMCAA"
50 | }
51 | }
52 | }
53 | }
54 | }
55 | ],
56 | "nextSyncUrl": "http://cdn.contentful.com/spaces/emh6o2ireilu/sync?sync_token=w5ZGw6JFwqZmVcKsE8Kow4grw45QdyYew4AvJMO0M2lFFcOkE2oaw50kwrUGHcKow7vDtcKbQ8KzIMKww73DvFvCq2TDmiLClS3DkwZVdncGXMKxXS3CgGQ3woUwHVnDlMKAIsO6w6DClkYfwprClsKfGw"
57 | }
58 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/CDAFallbackDictionary.m:
--------------------------------------------------------------------------------
1 | //
2 | // CDAFallbackDictionary.m
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 28/03/14.
6 | //
7 | //
8 |
9 | #import "CDAFallbackDictionary.h"
10 |
11 | @interface CDAFallbackDictionary ()
12 |
13 | @property (nonatomic) NSDictionary* actualDictionary;
14 | @property (nonatomic) NSDictionary* fallbackDictionary;
15 | @property (nonatomic, readonly) NSSet* keySet;
16 |
17 | @end
18 |
19 | #pragma mark -
20 |
21 | @implementation CDAFallbackDictionary
22 |
23 | -(NSUInteger)count {
24 | return self.keySet.count;
25 | }
26 |
27 | -(instancetype)initWithDictionary:(NSDictionary *)dict fallbackDictionary:(NSDictionary *)fallbackDict {
28 | self = [self initWithObjects:nil forKeys:nil count:0];
29 | if (self) {
30 | self.actualDictionary = dict;
31 | self.fallbackDictionary = fallbackDict;
32 | }
33 | return self;
34 | }
35 |
36 | -(instancetype)initWithObjects:(const __unsafe_unretained id [])objects
37 | forKeys:(const __unsafe_unretained id [])keys
38 | count:(NSUInteger)cnt {
39 | self = [super init];
40 | return self;
41 | }
42 |
43 | -(NSEnumerator *)keyEnumerator {
44 | return [self.keySet objectEnumerator];
45 | }
46 |
47 | -(NSSet*)keySet {
48 | NSMutableSet* keySet = [NSMutableSet setWithArray:self.actualDictionary.allKeys];
49 | [keySet addObjectsFromArray:self.fallbackDictionary.allKeys];
50 | return [keySet copy];
51 | }
52 |
53 | -(id)objectForKey:(id)key {
54 | id value = [self.actualDictionary objectForKey:key];
55 | return value ?: [self.fallbackDictionary objectForKey:key];
56 | }
57 |
58 | @end
59 |
--------------------------------------------------------------------------------
/Tests/Data/Fixtures/Crash-001.json:
--------------------------------------------------------------------------------
1 | {
2 | "fields": {
3 | "beacon": null,
4 | "beaconProximity": null,
5 | "mainHeadline": "Lorem Ipsum",
6 | "mainBody": "Lorem Ipsum",
7 | "teaserHeadline": "Lorem Ipsum",
8 | "teaserTextLong": "Lorem Ipsum",
9 | "teaserText": "Lorem Ipsum",
10 | "locationIsAll": false,
11 | "entryType": "Image and Text",
12 | "showTeaser": false,
13 | "channel": {
14 | "sys": {
15 | "id": "2IhhbTcar6iqeeUwGsieIW",
16 | "type": "Link",
17 | "linkType": "Entry"
18 | }
19 | },
20 | "multipleLocations": [
21 | {
22 | "sys": {
23 | "id": "3af3Ya0PheQiQGaIC6C0kI",
24 | "type": "Link",
25 | "linkType": "Entry"
26 | }
27 | }
28 | ],
29 | "mainImage": {
30 | "sys": {
31 | "id": "5u2CzLsv1S20gA4044GeEg",
32 | "type": "Link",
33 | "linkType": "Asset"
34 | }
35 | },
36 | "uuidAssgn": {
37 | "sys": {
38 | "id": "2lBvUjgDnmGKGmsM0wkem4",
39 | "type": "Link",
40 | "linkType": "Entry"
41 | }
42 | }
43 | },
44 | "sys": {
45 | "space": {
46 | "sys": {
47 | "type": "Link",
48 | "linkType": "Space",
49 | "id": "k7cpvwpbb4c0"
50 | }
51 | },
52 | "type": "Entry",
53 | "id": "5rpEqrj9UQ4eqAssqYmeOi",
54 | "contentType": {
55 | "sys": {
56 | "type": "Link",
57 | "linkType": "ContentType",
58 | "id": "2KZUNxrxfyYC8qO42o0oMQ"
59 | }
60 | },
61 | "revision": 10,
62 | "createdAt": "2014-10-21T20:46:58.471Z",
63 | "updatedAt": "2014-10-28T16:49:26.057Z",
64 | "locale": "en-US"
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/CDARequest.m:
--------------------------------------------------------------------------------
1 | //
2 | // CDARequest.m
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 10/03/14.
6 | //
7 | //
8 |
9 | #import "CDARequest+Private.h"
10 |
11 | @interface CDARequest ()
12 |
13 | @property (nonatomic) NSURLSessionTask* task;
14 |
15 | @end
16 |
17 | #pragma mark -
18 |
19 | @implementation CDARequest
20 |
21 | @dynamic error;
22 | @dynamic request;
23 | @dynamic response;
24 | @dynamic responseData;
25 | @dynamic responseObject;
26 | @dynamic responseString;
27 | @dynamic responseStringEncoding;
28 |
29 | #pragma mark -
30 |
31 | -(instancetype)initWithSessionTask:(NSURLSessionTask *)task {
32 | self = [super init];
33 | if (self) {
34 | self.task = task;
35 | }
36 | return self;
37 | }
38 |
39 | #pragma mark - Compatibility with 1.x API
40 |
41 | - (NSURLRequest *)request {
42 | return self.task.originalRequest;
43 | }
44 |
45 | - (NSStringEncoding)responseStringEncoding {
46 | NSString *encoding = self.task.response.textEncodingName;
47 |
48 | if (!encoding) {
49 | return NSUTF8StringEncoding;
50 | }
51 | return CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding((CFStringRef)encoding));
52 | }
53 |
54 | #pragma mark - Message forwarding to underlying AFHTTPRequestOperation
55 |
56 | -(void)forwardInvocation:(NSInvocation *)invocation {
57 | [invocation invokeWithTarget:self.task];
58 | }
59 |
60 | -(NSMethodSignature*)methodSignatureForSelector:(SEL)selector {
61 | NSMethodSignature *signature = [super methodSignatureForSelector:selector];
62 | if (!signature) {
63 | signature = [self.task methodSignatureForSelector:selector];
64 | }
65 | return signature;
66 | }
67 |
68 | @end
69 |
--------------------------------------------------------------------------------
/Tests/PreviewModeSyncTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // PreviewModeSyncTests.m
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 14/04/14.
6 | //
7 | //
8 |
9 | #import "SyncBaseTestCase.h"
10 |
11 | @interface PreviewModeSyncTests : SyncBaseTestCase
12 |
13 | @end
14 |
15 | #pragma mark -
16 |
17 | @implementation PreviewModeSyncTests
18 |
19 | -(CDAClient*)buildClient {
20 | CDAConfiguration* configuration = [CDAConfiguration defaultConfiguration];
21 | configuration.previewMode = YES;
22 | return [[CDAClient alloc] initWithSpaceKey:@"emh6o2ireilu" accessToken:@"3396581609dda9ddb19140eb8acb2216a9f33895b178e83a7dee7c75793c8243" configuration:configuration];
23 | }
24 |
25 | -(void)testInitialSync {
26 | XCTestExpectation *expectation = [self expectationWithDescription:@""];
27 |
28 | CDARequest* request = [self.client initialSynchronizationWithSuccess:^(CDAResponse *response, CDASyncedSpace *space) {
29 | XCTAssertEqual(2U, space.assets.count, @"");
30 | XCTAssertEqual(9U, space.entries.count, @"");
31 |
32 | [space performSynchronizationWithSuccess:^{
33 | XCTAssertEqual(2U, space.assets.count, @"");
34 | XCTAssertEqual(9U, space.entries.count, @"");
35 |
36 | [expectation fulfill];
37 | } failure:^(CDAResponse *response, NSError *error) {
38 | XCTFail(@"Error: %@", error);
39 |
40 | [expectation fulfill];
41 | }];
42 | } failure:^(CDAResponse *response, NSError *error) {
43 | XCTFail(@"Error: %@", error);
44 |
45 | [expectation fulfill];
46 | }];
47 | XCTAssertNotNil(request, @"");
48 |
49 | [self waitForExpectationsWithTimeout:10.0 handler:nil];
50 | }
51 |
52 | @end
53 |
--------------------------------------------------------------------------------
/Tests/Data/ComplexSyncTests/ComplexLinkTestUpdate2.json:
--------------------------------------------------------------------------------
1 | {
2 | "sys": {
3 | "type": "Array"
4 | },
5 | "items": [
6 | {
7 | "sys": {
8 | "space": {
9 | "sys": {
10 | "type": "Link",
11 | "linkType": "Space",
12 | "id": "emh6o2ireilu"
13 | }
14 | },
15 | "type": "Entry",
16 | "contentType": {
17 | "sys": {
18 | "type": "Link",
19 | "linkType": "ContentType",
20 | "id": "4yCmJfmk1WeqACagaemOIs"
21 | }
22 | },
23 | "id": "5ZmiC472OAg2SY2W0QM6Gs",
24 | "revision": 2,
25 | "createdAt": "2014-04-11T11:39:09.283Z",
26 | "updatedAt": "2014-04-11T11:41:29.967Z"
27 | },
28 | "fields": {
29 | "link1": {
30 | "en-US": {
31 | "sys": {
32 | "type": "Link",
33 | "linkType": "Entry",
34 | "id": "4upDPGUMMEkG8w8UUs2OiO"
35 | }
36 | }
37 | },
38 | "link2": {
39 | "en-US": {
40 | "sys": {
41 | "type": "Link",
42 | "linkType": "Entry",
43 | "id": "1gQ4P2tG7QaGkQwkC4a6Gg"
44 | }
45 | }
46 | },
47 | "link3": {
48 | "en-US": {
49 | "sys": {
50 | "type": "Link",
51 | "linkType": "Entry",
52 | "id": "1Wl5HnguK8CiaykiQAiGu6"
53 | }
54 | }
55 | }
56 | }
57 | }
58 | ],
59 | "nextSyncUrl": "https://cdn.contentful.com/spaces/emh6o2ireilu/sync?sync_token=w5ZGw6JFwqZmVcKsE8Kow4grw45QdyY0wpV-EsO_VcK9LDPCs8O0wpBiw7vCusOKesOZXsO9wqYTw5bCiBQZacKGwolKexPDtxApQcKvwoPClcKtSWzCgFvDrnBHAsKrwqHDth_CvgbCiTkFw4rCpygefTsj"
60 | }
61 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI.podspec:
--------------------------------------------------------------------------------
1 | #!/usr/bin/ruby
2 |
3 | require 'dotenv/load'
4 |
5 | Pod::Spec.new do |s|
6 | s.name = "ContentfulDeliveryAPI"
7 | s.version = ENV['DELIVERY_SDK_VERSION']
8 | s.summary = "Objective-C SDK for Contentful's Content Delivery API."
9 | s.homepage = "https://github.com/contentful/contentful.objc/"
10 | s.social_media_url = 'https://twitter.com/contentful'
11 |
12 | s.license = {
13 | :type => 'MIT',
14 | :file => 'LICENSE'
15 | }
16 |
17 | s.authors = { "Boris Bügling" => "boris@buegling.com", "JP Wright" => "jp@contentful.com" }
18 | s.source = { :git => "https://github.com/contentful/contentful.objc.git",
19 | :tag => "Delivery-#{s.version.to_s}" }
20 | s.requires_arc = true
21 |
22 | s.source_files = [
23 | 'ContentfulDeliveryAPI/Resources/*.{h,m}',
24 | 'ContentfulDeliveryAPI/*.{h,m}',
25 | 'Versions.h'
26 | ]
27 | s.public_header_files = [
28 | 'ContentfulDeliveryAPI/Resources/{CDAArray,CDAAsset,CDAContentType,CDAEntry,CDAError,CDASpace,CDAResource}.h',
29 | 'ContentfulDeliveryAPI/{CDAClient,CDAConfiguration,CDANullabilityStubs,CDARequest,CDAResponse,CDAField,CDASyncedSpace,ContentfulDeliveryAPI,CDAPersistenceManager,CDAPersistedAsset,CDAPersistedEntry,CDAPersistedSpace,CDALocalizablePersistedEntry,CDALocalizedPersistedEntry}.h'
30 | ]
31 | # iOS specific
32 | s.ios.deployment_target = '9.0'
33 | s.ios.frameworks = 'UIKit', 'MapKit'
34 |
35 | # macOS specific
36 | s.osx.deployment_target = '10.12'
37 |
38 | # tvOS specific
39 | s.tvos.deployment_target = '9.0'
40 | s.tvos.frameworks = 'UIKit', 'MapKit'
41 |
42 |
43 | s.dependency 'AFNetworking', '~> 3.2.1'
44 | s.dependency 'ISO8601', '~> 0.6.0'
45 | end
46 |
47 |
--------------------------------------------------------------------------------
/Tests/Data/Recordings/UtilityTests.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "body" : "ewogICJzeXMiOiB7CiAgICAidHlwZSI6ICJTcGFjZSIsCiAgICAiaWQiOiAiY2Zl\r\neGFtcGxlYXBpIgogIH0sCiAgIm5hbWUiOiAiQ29udGVudGZ1bCBFeGFtcGxlIEFQ\r\nSSIsCiAgImxvY2FsZXMiOiBbCiAgICB7CiAgICAgICJjb2RlIjogImVuLVVTIiwK\r\nICAgICAgImRlZmF1bHQiOiB0cnVlLAogICAgICAibmFtZSI6ICJFbmdsaXNoIgog\r\nICAgfSwKICAgIHsKICAgICAgImNvZGUiOiAidGxoIiwKICAgICAgImRlZmF1bHQi\r\nOiBmYWxzZSwKICAgICAgIm5hbWUiOiAiS2xpbmdvbiIKICAgIH0KICBdCn0K",
4 | "headers" : {
5 | "Access-Control-Allow-Headers" : "Accept,Accept-Language,Authorization,Cache-Control,Content-Length,Content-Range,Content-Type,DNT,Destination,Expires,If-Match,If-Modified-Since,If-None-Match,Keep-Alive,Last-Modified,Origin,Pragma,Range,User-Agent,X-Http-Method-Override,X-Mx-ReqToken,X-Requested-With,X-Contentful-Version,X-Contentful-Content-Type,X-Contentful-Organization",
6 | "Cache-Control" : "max-age=0",
7 | "Vary" : "Accept-Encoding",
8 | "Access-Control-Allow-Origin" : "*",
9 | "X-Cache-Hits" : "1",
10 | "Etag" : "\"14a17843cf0cf8b116801f96c1c6fe23\"",
11 | "Content-Length" : "285",
12 | "Keep-Alive" : "timeout=10, max=50",
13 | "Access-Control-Max-Age" : "86400",
14 | "Connection" : "Keep-Alive",
15 | "Accept-Ranges" : "bytes",
16 | "X-Served-By" : "cache-fra1232-FRA",
17 | "Content-Type" : "application\/vnd.contentful.delivery.v1+json",
18 | "X-Cache" : "HIT",
19 | "Via" : "1.1 varnish",
20 | "Server" : "nginx\/1.1.19",
21 | "Access-Control-Allow-Methods" : "GET,HEAD,OPTIONS",
22 | "X-Contentful-Request-Id" : "f1c-737785047",
23 | "Age" : "574",
24 | "Date" : "Mon, 28 Apr 2014 14:01:49 GMT"
25 | },
26 | "method" : "GET",
27 | "status" : 200,
28 | "uri" : "https:\/\/cdn.contentful.com\/spaces\/cfexampleapi\/"
29 | }
30 | ]
--------------------------------------------------------------------------------
/Tests/Data/SyncTests/asset-multiple-locales.json:
--------------------------------------------------------------------------------
1 | {
2 | "sys": {
3 | "type": "Array"
4 | },
5 | "total": 1,
6 | "skip": 0,
7 | "limit": 100,
8 | "items": [
9 | {
10 | "sys": {
11 | "space": {
12 | "sys": {
13 | "type": "Link",
14 | "linkType": "Space",
15 | "id": "bht13amj0fva"
16 | }
17 | },
18 | "id": "14bZJKTr6AoaGyeg4kYiWq",
19 | "type": "Asset",
20 | "createdAt": "2016-10-05T14:31:36.082Z",
21 | "updatedAt": "2016-10-05T14:31:36.082Z",
22 | "revision": 1
23 | },
24 | "fields": {
25 | "title": {
26 | "en-US": "EN Title",
27 | "es": "ES Title"
28 | },
29 | "description": {
30 | "en-US": "EN Description",
31 | "es": "ES Description"
32 | },
33 | "file": {
34 | "en-US": {
35 | "url": "//assets.contentful.com/bht13amj0fva/14bZJKTr6AoaGyeg4kYiWq/13f00bdf75c1320061ce471a3881e831/Flag_of_the_United_States.svg",
36 | "details": {
37 | "size": 899
38 | },
39 | "fileName": "Flag_of_the_United_States.svg",
40 | "contentType": "image/svg+xml"
41 | },
42 | "es": {
43 | "url": "//assets.contentful.com/bht13amj0fva/14bZJKTr6AoaGyeg4kYiWq/5501c98c296af77b9acba1146ea3e211/Flag_of_Spain.svg",
44 | "details": {
45 | "size": 60255
46 | },
47 | "fileName": "Flag_of_Spain.svg",
48 | "contentType": "image/svg+xml"
49 | }
50 | }
51 | }
52 | }
53 | ]
54 | }
55 |
--------------------------------------------------------------------------------
/Tests/Data/ComplexSyncTests/ComplexLinkTestContentTypes2.json:
--------------------------------------------------------------------------------
1 | {
2 | "sys": {
3 | "type": "Array"
4 | },
5 | "total": 2,
6 | "skip": 0,
7 | "limit": 100,
8 | "items": [
9 | {
10 | "fields": [
11 | {
12 | "name": "such field",
13 | "id": "suchField",
14 | "type": "Symbol"
15 | }
16 | ],
17 | "name": "⚡️ new content type",
18 | "sys": {
19 | "space": {
20 | "sys": {
21 | "type": "Link",
22 | "linkType": "Space",
23 | "id": "emh6o2ireilu"
24 | }
25 | },
26 | "type": "ContentType",
27 | "id": "5kLp8FbRwAG0kcOOYa6GMa",
28 | "revision": 1,
29 | "createdAt": "2014-04-11T08:39:04.421Z",
30 | "updatedAt": "2014-04-11T08:39:04.421Z"
31 | },
32 | "displayField": "suchField"
33 | },
34 | {
35 | "fields": [
36 | {
37 | "name": "link1",
38 | "id": "link1",
39 | "type": "Link",
40 | "linkType": "Entry"
41 | },
42 | {
43 | "name": "link2",
44 | "id": "link2",
45 | "type": "Link",
46 | "linkType": "Entry"
47 | },
48 | {
49 | "name": "link3",
50 | "id": "link3",
51 | "type": "Link",
52 | "linkType": "Entry"
53 | }
54 | ],
55 | "name": "ThreeLinks to other Entries",
56 | "sys": {
57 | "space": {
58 | "sys": {
59 | "type": "Link",
60 | "linkType": "Space",
61 | "id": "emh6o2ireilu"
62 | }
63 | },
64 | "type": "ContentType",
65 | "id": "4yCmJfmk1WeqACagaemOIs",
66 | "revision": 1,
67 | "createdAt": "2014-04-11T11:38:32.120Z",
68 | "updatedAt": "2014-04-11T11:38:32.120Z"
69 | }
70 | }
71 | ]
72 | }
73 |
--------------------------------------------------------------------------------
/Tests/StagingTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // StagingTests.m
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 06/03/14.
6 | //
7 | //
8 |
9 | #import "ContentfulBaseTestCase.h"
10 |
11 | @interface StagingTests : ContentfulBaseTestCase
12 |
13 | @end
14 |
15 | #pragma mark -
16 |
17 | @implementation StagingTests
18 |
19 | // FIXME: Source space has been deleted, test data needs to be recreated
20 | #if 0
21 | - (void)setUp
22 | {
23 | [super setUp];
24 |
25 | CDAConfiguration* configuration = [CDAConfiguration defaultConfiguration];
26 | configuration.server = @"cdn.flinkly.com";
27 |
28 | self.client = [[CDAClient alloc] initWithSpaceKey:@"3vysoudsmwwo" accessToken:@"8efdb99a1b33b21edd6bd6f68aa702a0d688b4a4433ac3327d234a28ed825ca2" configuration:configuration];
29 | }
30 |
31 | - (void)testContentTypes {
32 | XCTestExpectation *expectation = [self expectationWithDescription:@""];
33 |
34 | [self.client fetchContentTypesWithSuccess:^(CDAResponse *response, CDAArray *array) {
35 | XCTAssertNotNil(array, @"");
36 |
37 | [expectation fulfill];
38 | } failure:^(CDAResponse *response, NSError *error) {
39 | XCTFail(@"Error: %@", error);
40 |
41 | [expectation fulfill];
42 | }];
43 |
44 | [self waitForExpectationsWithTimeout:10.0 handler:nil];
45 | }
46 |
47 | - (void)testEntries {
48 | XCTestExpectation *expectation = [self expectationWithDescription:@""];
49 |
50 | [self.client fetchEntriesWithSuccess:^(CDAResponse *response, CDAArray *array) {
51 | XCTAssertNotNil(array, @"");
52 |
53 | [expectation fulfill];
54 | } failure:^(CDAResponse *response, NSError *error) {
55 | XCTFail(@"Error: %@", error);
56 |
57 | [expectation fulfill];
58 | }];
59 |
60 | [self waitForExpectationsWithTimeout:10.0 handler:nil];
61 | }
62 | #endif
63 |
64 | @end
65 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/CDAContentTypeRegistry.m:
--------------------------------------------------------------------------------
1 | //
2 | // CDAContentTypeRegistry.m
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 04/03/14.
6 | //
7 | //
8 |
9 | #import "CDAContentType.h"
10 |
11 | #import "CDAContentTypeRegistry.h"
12 |
13 | @interface CDAContentTypeRegistry ()
14 |
15 | @property (nonatomic) NSMutableDictionary* contentTypes;
16 | @property (nonatomic) NSMutableDictionary* customClasses;
17 |
18 | @end
19 |
20 | #pragma mark -
21 |
22 | @implementation CDAContentTypeRegistry
23 |
24 | -(void)addContentType:(CDAContentType*)contentType {
25 | @synchronized(self) {
26 | NSAssert(contentType.identifier, @"Content Type needs an identifier");
27 | self.contentTypes[contentType.identifier] = contentType;
28 | }
29 | }
30 |
31 | -(CDAContentType*)contentTypeForIdentifier:(NSString*)identifier {
32 | return self.contentTypes[identifier];
33 | }
34 |
35 | -(id)copyWithZone:(NSZone *)zone {
36 | CDAContentTypeRegistry* copy = [[[self class] allocWithZone:zone] init];
37 | copy.contentTypes = self.contentTypes;
38 | copy.customClasses = self.customClasses;
39 | return copy;
40 | }
41 |
42 | -(Class)customClassForContentType:(CDAContentType *)contentType {
43 | return self.customClasses[contentType.identifier];
44 | }
45 |
46 | -(BOOL)hasCustomClasses {
47 | return self.customClasses.count > 0;
48 | }
49 |
50 | -(instancetype)init {
51 | self = [super init];
52 | if (self) {
53 | self.contentTypes = [@{} mutableCopy];
54 | self.customClasses = [@{} mutableCopy];
55 | }
56 | return self;
57 | }
58 |
59 | -(void)registerClass:(Class)customClass forContentType:(CDAContentType*)contentType {
60 | self.customClasses[contentType.identifier] = customClass;
61 | }
62 |
63 | -(void)registerClass:(Class)customClass forContentTypeWithIdentifier:(NSString*)identifier {
64 | self.customClasses[identifier] = customClass;
65 | }
66 |
67 | @end
68 |
--------------------------------------------------------------------------------
/Tests/LocaleTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // LocaleTests.m
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 19/08/15.
6 | //
7 | //
8 |
9 | #import "ContentfulBaseTestCase.h"
10 |
11 | @interface LocaleTests : ContentfulBaseTestCase
12 |
13 | @end
14 |
15 | #pragma mark -
16 |
17 | @implementation LocaleTests
18 |
19 | -(void)testFallbackLocalesForAssets {
20 | XCTestExpectation *expectation = [self expectationWithDescription:@""];
21 |
22 | self.client = [[CDAClient alloc] initWithSpaceKey:@"dmm6iymtengv"
23 | accessToken:@"b18e713cf2c3c8916cad0cca8e801a3c230e9e6781098dc50fb0810ebc36a4a1"];
24 |
25 | [self.client fetchAssetsMatching:@{ @"locale": @"*" } success:^(CDAResponse* r, CDAArray* array) {
26 | CDAAsset* asset = array.items.firstObject;
27 | XCTAssertNotNil(asset.URL);
28 |
29 | asset.locale = @"es";
30 | XCTAssertNotNil(asset.URL);
31 |
32 | [expectation fulfill];
33 | } failure:^(CDAResponse* response, NSError* error) {
34 | XCTFail(@"Error: %@", error);
35 |
36 | [expectation fulfill];
37 | }];
38 |
39 | [self waitForExpectationsWithTimeout:10.0 handler:nil];
40 | }
41 |
42 | -(void)testWildcardLocales {
43 | XCTestExpectation *expectation = [self expectationWithDescription:@""];
44 |
45 | [self.client fetchEntriesMatching:@{ @"locale": @"*", @"sys.id": @"nyancat" }
46 | success:^(CDAResponse* response, CDAArray* array) {
47 | NSLog(@"yolo: %@", array);
48 |
49 | [expectation fulfill];
50 | } failure:^(CDAResponse* response, NSError* error) {
51 | XCTFail(@"Error: %@", error);
52 |
53 | [expectation fulfill];
54 | }];
55 |
56 | [self waitForExpectationsWithTimeout:10.0 handler:nil];
57 | }
58 |
59 | @end
60 |
--------------------------------------------------------------------------------
/Tests/LinkedData.xcdatamodeld/LinkedData.xcdatamodel/contents:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/Tests/AddContentTypesSyncTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // AddContentTypesSyncTests.m
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 11/04/14.
6 | //
7 | //
8 |
9 | #import "SyncBaseTestCase.h"
10 | @import XCTest;
11 |
12 | @interface AddContentTypesSyncTests : SyncBaseTestCase
13 |
14 | @end
15 |
16 | #pragma mark -
17 |
18 | @implementation AddContentTypesSyncTests
19 |
20 | -(void)setUp {
21 | [super setUp];
22 |
23 | /*
24 | Map URLs to JSON response files
25 | */
26 | NSDictionary* stubs = @{ @"https://cdn.contentful.com/spaces/emh6o2ireilu/sync?initial=true": @"AddContentTypesInitial", @"https://cdn.contentful.com/spaces/emh6o2ireilu/sync?sync_token=w5ZGw6JFwqZmVcKsE8Kow4grw45QdybCr1IuSMKBHcKNbynCrcOdF8KoNCA_cwJHKx5VfW1EMsOBdkFww5_CjcOMQcOQw4_Dg8KjNcK8w7RrYCY8w57DmjM5wprDgcOxw7JOw7jDuQjDgsKVTsKBw7HDvcOX": @"AddContentTypesUpdate", @"https://cdn.contentful.com/spaces/emh6o2ireilu/": @"space", @"https://cdn.contentful.com/spaces/emh6o2ireilu/content_types?limit=1&sys.id%5Bin%5D=5kLp8FbRwAG0kcOOYa6GMa": @"AddContentTypesContentTypes", };
27 |
28 | [self stubHTTPRequestUsingFixtures:stubs inDirectory:@"ComplexSyncTests"];
29 | }
30 |
31 | -(void)testAddContentTypesDuringSyncSession {
32 | XCTestExpectation *expectation = [self expectationWithDescription:@""];
33 |
34 | CDARequest* request = [self.client initialSynchronizationWithSuccess:^(CDAResponse *response, CDASyncedSpace *space) {
35 | space.delegate = self;
36 |
37 | [space performSynchronizationWithSuccess:^{
38 | [expectation fulfill];
39 | } failure:^(CDAResponse *response, NSError *error) {
40 | XCTFail(@"Error: %@", error);
41 |
42 | [expectation fulfill];
43 | }];
44 | } failure:^(CDAResponse *response, NSError *error) {
45 | XCTFail(@"Error: %@", error);
46 |
47 | [expectation fulfill];
48 | }];
49 | XCTAssertNotNil(request, @"");
50 |
51 | [self waitForExpectationsWithTimeout:10.0 handler:nil];
52 |
53 | XCTAssertEqual(1U, self.numberOfEntriesCreated, @"");
54 | }
55 |
56 | @end
57 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/Resources/CDASpace.m:
--------------------------------------------------------------------------------
1 | //
2 | // CDASpace.m
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 06/03/14.
6 | //
7 | //
8 |
9 | #import "CDAResource+Private.h"
10 | #import "CDASpace+Private.h"
11 |
12 | @interface CDASpace ()
13 |
14 | @property (nonatomic) NSString* name;
15 |
16 | @end
17 |
18 | #pragma mark -
19 |
20 | @implementation CDASpace
21 |
22 | +(NSString *)CDAType {
23 | return @"Space";
24 | }
25 |
26 | #pragma mark -
27 |
28 | -(instancetype)initWithDictionary:(NSDictionary *)dictionary
29 | client:(CDAClient*)client
30 | localizationAvailable:(BOOL)localizationAvailable {
31 | self = [super initWithDictionary:dictionary client:client localizationAvailable:localizationAvailable];
32 | if (self) {
33 | self.defaultLocale = @"en-US";
34 | self.locales = dictionary[@"locales"];
35 | self.name = dictionary[@"name"];
36 |
37 | for (NSDictionary* locale in self.locales) {
38 | if ([locale[@"default"] boolValue] && locale[@"code"]) {
39 | NSString* code = locale[@"code"];
40 | self.defaultLocale = code;
41 | }
42 | }
43 | }
44 | return self;
45 | }
46 |
47 | -(NSArray *)localeCodes {
48 | return [self.locales valueForKey:@"code"] ?: @[ self.defaultLocale ];
49 | }
50 |
51 | // We only encode properties that have write permissions
52 | #pragma mark - NSCoding
53 |
54 | - (instancetype)initWithCoder:(NSCoder *)aDecoder {
55 | self = [super initWithCoder:aDecoder];
56 | if (self) {
57 | self.name = [aDecoder decodeObjectForKey:@"name"];
58 | self.defaultLocale = [aDecoder decodeObjectForKey:@"defaultLocale"];
59 | self.locales = [aDecoder decodeObjectForKey:@"locales"];
60 | }
61 | return self;
62 | }
63 |
64 | - (void)encodeWithCoder:(NSCoder *)aCoder {
65 | [super encodeWithCoder:aCoder];
66 |
67 | [aCoder encodeObject:self.name forKey:@"name"];
68 | [aCoder encodeObject:self.defaultLocale forKey:@"defaultLocale"];
69 | [aCoder encodeObject:self.locales forKey:@"locales"];
70 | }
71 |
72 | @end
73 |
--------------------------------------------------------------------------------
/ContentfulSDK.xcodeproj/xcshareddata/xcschemes/ManagementTests.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
14 |
15 |
17 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
39 |
40 |
41 |
42 |
48 |
49 |
51 |
52 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/Tests/Data/ComplexSyncTests/LinkTestUpdate.json:
--------------------------------------------------------------------------------
1 | {
2 | "sys": {
3 | "type": "Array"
4 | },
5 | "items": [
6 | {
7 | "sys": {
8 | "space": {
9 | "sys": {
10 | "type": "Link",
11 | "linkType": "Space",
12 | "id": "emh6o2ireilu"
13 | }
14 | },
15 | "type": "Entry",
16 | "contentType": {
17 | "sys": {
18 | "type": "Link",
19 | "linkType": "ContentType",
20 | "id": "6bAvxqodl6s4MoKuWYkmqe"
21 | }
22 | },
23 | "id": "1Wl5HnguK8CiaykiQAiGu6",
24 | "revision": 1,
25 | "createdAt": "2014-04-09T11:48:47.866Z",
26 | "updatedAt": "2014-04-09T11:48:47.866Z"
27 | },
28 | "fields": {
29 | "title": {
30 | "en-US": "WithCategory"
31 | },
32 | "body": {
33 | "en-US": "some text"
34 | },
35 | "category": {
36 | "en-US": {
37 | "sys": {
38 | "type": "Link",
39 | "linkType": "Entry",
40 | "id": "6nRlw4CofeeICEYgIqaIIg"
41 | }
42 | }
43 | }
44 | }
45 | },
46 | {
47 | "sys": {
48 | "space": {
49 | "sys": {
50 | "type": "Link",
51 | "linkType": "Space",
52 | "id": "emh6o2ireilu"
53 | }
54 | },
55 | "type": "Entry",
56 | "contentType": {
57 | "sys": {
58 | "type": "Link",
59 | "linkType": "ContentType",
60 | "id": "51LZmvenywOe8aig28sCgY"
61 | }
62 | },
63 | "id": "6nRlw4CofeeICEYgIqaIIg",
64 | "revision": 1,
65 | "createdAt": "2014-04-09T11:48:42.407Z",
66 | "updatedAt": "2014-04-09T11:48:42.407Z"
67 | },
68 | "fields": {
69 | "name": {
70 | "en-US": "foobar"
71 | }
72 | }
73 | }
74 | ],
75 | "nextSyncUrl": "http://cdn.contentful.com/spaces/emh6o2ireilu/sync?sync_token=w5ZGw6JFwqZmVcKsE8Kow4grw45QdyZ7T8Obw5Inwoh6Tk7Cq8KUDcK7w5ssw6vCgjLDjk9Hwr3DusOzw7XCo8OIwo3CicK5SBkqCcK7woDDhSjCkMOGw7rCqMOtE1V1L3LDq8KIck_DssK4K8OBe0vDn0vDrXjDkMOf"
76 | }
77 |
--------------------------------------------------------------------------------
/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - AFNetworking (3.2.1):
3 | - AFNetworking/NSURLSession (= 3.2.1)
4 | - AFNetworking/Reachability (= 3.2.1)
5 | - AFNetworking/Security (= 3.2.1)
6 | - AFNetworking/Serialization (= 3.2.1)
7 | - AFNetworking/UIKit (= 3.2.1)
8 | - AFNetworking/NSURLSession (3.2.1):
9 | - AFNetworking/Reachability
10 | - AFNetworking/Security
11 | - AFNetworking/Serialization
12 | - AFNetworking/Reachability (3.2.1)
13 | - AFNetworking/Security (3.2.1)
14 | - AFNetworking/Serialization (3.2.1)
15 | - AFNetworking/UIKit (3.2.1):
16 | - AFNetworking/NSURLSession
17 | - CCLRequestReplay (0.9.0):
18 | - CCLRequestReplay/Blueprint (= 0.9.0)
19 | - CCLRequestReplay/JSON (= 0.9.0)
20 | - CCLRequestReplay/Manager (= 0.9.0)
21 | - CCLRequestReplay/Record (= 0.9.0)
22 | - CCLRequestReplay/Replay (= 0.9.0)
23 | - CCLRequestReplay/Blueprint (0.9.0)
24 | - CCLRequestReplay/JSON (0.9.0)
25 | - CCLRequestReplay/Manager (0.9.0)
26 | - CCLRequestReplay/Record (0.9.0)
27 | - CCLRequestReplay/Replay (0.9.0)
28 | - FBSnapshotTestCase/Core (2.1.4)
29 | - ISO8601 (0.6.0)
30 | - OCMock (3.4.2)
31 | - VCRURLConnection (0.2.4)
32 |
33 | DEPENDENCIES:
34 | - AFNetworking (~> 3.2.1)
35 | - CCLRequestReplay (from `https://github.com/neonichu/CCLRequestReplay.git`)
36 | - FBSnapshotTestCase/Core
37 | - ISO8601 (~> 0.6.0)
38 | - OCMock
39 | - VCRURLConnection (= 0.2.4)
40 |
41 | SPEC REPOS:
42 | https://github.com/cocoapods/specs.git:
43 | - AFNetworking
44 | - FBSnapshotTestCase
45 | - ISO8601
46 | - OCMock
47 | - VCRURLConnection
48 |
49 | EXTERNAL SOURCES:
50 | CCLRequestReplay:
51 | :git: https://github.com/neonichu/CCLRequestReplay.git
52 |
53 | CHECKOUT OPTIONS:
54 | CCLRequestReplay:
55 | :commit: e2d771c32c5327ef18b367acaed299e3c841b9ed
56 | :git: https://github.com/neonichu/CCLRequestReplay.git
57 |
58 | SPEC CHECKSUMS:
59 | AFNetworking: b6f891fdfaed196b46c7a83cf209e09697b94057
60 | CCLRequestReplay: a472e52da260c28d7a41df76697b8e518625a44f
61 | FBSnapshotTestCase: 094f9f314decbabe373b87cc339bea235a63e07a
62 | ISO8601: d3ea3ba9b752820cf92c6b47a9ee327e9f0e13fc
63 | OCMock: ebe9ee1dca7fbed0ff9193ac0b3e2d8862ea56f6
64 | VCRURLConnection: c522ba51c372f6ec79df4f0cd2cb0ac6cdb8ad65
65 |
66 | PODFILE CHECKSUM: 71937c87938d073786a8178ad3cc2c56124d65da
67 |
68 | COCOAPODS: 1.5.3
69 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/Resources/CDAError.m:
--------------------------------------------------------------------------------
1 | //
2 | // CDAError.m
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 05/03/14.
6 | //
7 | //
8 |
9 | #import "CDAError+Private.h"
10 | #import "CDAResource+Private.h"
11 |
12 | NSString* const CDAErrorDomain = @"CDAErrorDomain";
13 |
14 | @interface CDAError ()
15 |
16 | @property (nonatomic) NSDictionary* details;
17 | @property (nonatomic) NSString* message;
18 |
19 | @end
20 |
21 | #pragma mark -
22 |
23 | @implementation CDAError
24 |
25 | +(NSError*)buildErrorWithCode:(NSInteger)code userInfo:(NSDictionary*)userInfo {
26 | return [NSError errorWithDomain:CDAErrorDomain
27 | code:code
28 | userInfo:userInfo];
29 | }
30 |
31 | +(NSString *)CDAType {
32 | return @"Error";
33 | }
34 |
35 | #pragma mark -
36 |
37 | -(NSString *)description {
38 | return [[self errorRepresentationWithCode:0] description];
39 | }
40 |
41 | -(NSError *)errorRepresentationWithCode:(NSInteger)code {
42 | return [[self class] buildErrorWithCode:code
43 | userInfo:@{ @"details": self.details ?: @{},
44 | @"identifier": self.identifier,
45 | NSLocalizedDescriptionKey: self.message ?: @"" }];
46 | }
47 |
48 | -(instancetype)initWithDictionary:(NSDictionary *)dictionary
49 | client:(CDAClient*)client
50 | localizationAvailable:(BOOL)localizationAvailable {
51 | self = [super initWithDictionary:dictionary client:client localizationAvailable:localizationAvailable];
52 | if (self) {
53 | self.details = dictionary[@"details"];
54 | self.message = dictionary[@"message"];
55 | }
56 | return self;
57 | }
58 |
59 | // We only encode properties that have write permissions
60 | #pragma mark - NSCoding
61 |
62 | - (instancetype)initWithCoder:(NSCoder *)aDecoder {
63 | self = [super initWithCoder:aDecoder];
64 | if (self) {
65 | self.details = [aDecoder decodeObjectForKey:@"details"];
66 | self.message = [aDecoder decodeObjectForKey:@"message"];
67 | }
68 | return self;
69 | }
70 |
71 | - (void)encodeWithCoder:(NSCoder *)aCoder {
72 | [super encodeWithCoder:aCoder];
73 |
74 | [aCoder encodeObject:self.details forKey:@"details"];
75 | [aCoder encodeObject:self.message forKey:@"message"];
76 | }
77 |
78 | @end
79 |
--------------------------------------------------------------------------------
/Tests/Data/SyncTests/initialWithoutToken.json:
--------------------------------------------------------------------------------
1 | {
2 | "sys": {
3 | "type": "Array"
4 | },
5 | "items": [
6 | {
7 | "fields": {
8 | "title": {
9 | "en-US": "contentful-logo"
10 | },
11 | "file": {
12 | "en-US": {
13 | "fileName": "512_black.png",
14 | "contentType": "image/png",
15 | "details": {
16 | "image": {
17 | "width": 512,
18 | "height": 512
19 | },
20 | "size": 4189
21 | },
22 | "url": "//images.contentful.com/emh6o2ireilu/2q1Ns7Oygo2mAgoweuMCAA/7a4eb574952f359b851b3f353573b708/512_black.png"
23 | }
24 | }
25 | },
26 | "sys": {
27 | "space": {
28 | "sys": {
29 | "type": "Link",
30 | "linkType": "Space",
31 | "id": "emh6o2ireilu"
32 | }
33 | },
34 | "type": "Asset",
35 | "id": "2q1Ns7Oygo2mAgoweuMCAA",
36 | "revision": 1,
37 | "createdAt": "2014-03-25T11:01:41.057Z",
38 | "updatedAt": "2014-03-25T11:01:41.057Z"
39 | }
40 | },
41 | {
42 | "sys": {
43 | "space": {
44 | "sys": {
45 | "type": "Link",
46 | "linkType": "Space",
47 | "id": "emh6o2ireilu"
48 | }
49 | },
50 | "type": "Entry",
51 | "contentType": {
52 | "sys": {
53 | "type": "Link",
54 | "linkType": "ContentType",
55 | "id": "6bAvxqodl6s4MoKuWYkmqe"
56 | }
57 | },
58 | "id": "4upDPGUMMEkG8w8UUs2OiO",
59 | "revision": 1,
60 | "createdAt": "2014-03-25T11:00:43.065Z",
61 | "updatedAt": "2014-03-25T11:00:43.065Z"
62 | },
63 | "fields": {
64 | "title": {
65 | "en-US": "Test"
66 | },
67 | "body": {
68 | "en-US": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
69 | }
70 | }
71 | }
72 | ]
73 | }
74 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/CDARequestOperationManager.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDARequestOperationManager.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 06/03/14.
6 | //
7 | //
8 |
9 | #import
10 | #import "CDAClient.h"
11 |
12 | @class CDARequest;
13 |
14 | @interface CDARequestOperationManager : AFHTTPSessionManager
15 |
16 | -(instancetype)initWithSpaceKey:(NSString *)spaceKey
17 | accessToken:(NSString *)accessToken
18 | client:(CDAClient*)client
19 | configuration:(CDAConfiguration*)configuration
20 | isCMARequest:(BOOL)isCMARequest;
21 |
22 | -(CDARequest*)deleteURLPath:(NSString*)URLPath
23 | headers:(NSDictionary*)headers
24 | parameters:(NSDictionary*)parameters
25 | success:(CDAObjectFetchedBlock)success
26 | failure:(CDARequestFailureBlock)failure;
27 | -(CDARequest*)fetchArrayAtURLPath:(NSString*)URLPath
28 | parameters:(NSDictionary*)parameters
29 | success:(CDAArrayFetchedBlock)success
30 | failure:(CDARequestFailureBlock)failure;
31 | -(CDAArray*)fetchArraySynchronouslyAtURLPath:(NSString*)URLPath
32 | parameters:(NSDictionary*)parameters
33 | error:(NSError **)error;
34 | -(CDARequest*)fetchSpaceWithSuccess:(CDASpaceFetchedBlock)success
35 | failure:(CDARequestFailureBlock)failure;
36 | -(CDARequest*)fetchURLPath:(NSString*)URLPath
37 | parameters:(NSDictionary*)parameters
38 | success:(CDAObjectFetchedBlock)success
39 | failure:(CDARequestFailureBlock)failure;
40 |
41 | -(CDARequest*)postURLPath:(NSString*)URLPath
42 | headers:(NSDictionary*)headers
43 | parameters:(NSDictionary*)parameters
44 | success:(CDAObjectFetchedBlock)success
45 | failure:(CDARequestFailureBlock)failure;
46 | -(CDARequest*)putURLPath:(NSString*)URLPath
47 | headers:(NSDictionary*)headers
48 | parameters:(NSDictionary*)parameters
49 | success:(CDAObjectFetchedBlock)success
50 | failure:(CDARequestFailureBlock)failure;
51 |
52 | + (NSData *)sendSynchronousRequest:(NSURLRequest *)request
53 | returningResponse:(__autoreleasing NSURLResponse **)responsePtr
54 | error:(__autoreleasing NSError **)errorPtr;
55 |
56 | @end
57 |
--------------------------------------------------------------------------------
/Tests/Data/ComplexSyncTests/NewEntryAndDeletionUpdate.json:
--------------------------------------------------------------------------------
1 | {
2 | "sys": {
3 | "type": "Array"
4 | },
5 | "items": [
6 | {
7 | "sys": {
8 | "space": {
9 | "sys": {
10 | "type": "Link",
11 | "linkType": "Space",
12 | "id": "emh6o2ireilu"
13 | }
14 | },
15 | "type": "Entry",
16 | "contentType": {
17 | "sys": {
18 | "type": "Link",
19 | "linkType": "ContentType",
20 | "id": "6bAvxqodl6s4MoKuWYkmqe"
21 | }
22 | },
23 | "id": "42yYtmO46IY0GO2UCgOK2o",
24 | "revision": 1,
25 | "createdAt": "2014-04-10T09:37:06.719Z",
26 | "updatedAt": "2014-04-10T09:37:06.719Z"
27 | },
28 | "fields": {
29 | "title": {
30 | "en-US": "NewOneWithLinkToFoobar"
31 | },
32 | "body": {
33 | "en-US": "foo"
34 | },
35 | "category": {
36 | "en-US": {
37 | "sys": {
38 | "type": "Link",
39 | "linkType": "Entry",
40 | "id": "6nRlw4CofeeICEYgIqaIIg"
41 | }
42 | }
43 | }
44 | }
45 | },
46 | {
47 | "sys": {
48 | "space": {
49 | "sys": {
50 | "type": "Link",
51 | "linkType": "Space",
52 | "id": "emh6o2ireilu"
53 | }
54 | },
55 | "type": "Entry",
56 | "contentType": {
57 | "sys": {
58 | "type": "Link",
59 | "linkType": "ContentType",
60 | "id": "6bAvxqodl6s4MoKuWYkmqe"
61 | }
62 | },
63 | "id": "1Wl5HnguK8CiaykiQAiGu6",
64 | "revision": 3,
65 | "createdAt": "2014-04-09T11:48:47.866Z",
66 | "updatedAt": "2014-04-10T09:36:40.283Z"
67 | },
68 | "fields": {
69 | "title": {
70 | "en-US": "WithCategory"
71 | },
72 | "body": {
73 | "en-US": "some text"
74 | },
75 | "category": {
76 | "en-US": null
77 | },
78 | "picture": {
79 | "en-US": {
80 | "sys": {
81 | "type": "Link",
82 | "linkType": "Asset",
83 | "id": "2q1Ns7Oygo2mAgoweuMCAA"
84 | }
85 | }
86 | }
87 | }
88 | }
89 | ],
90 | "nextSyncUrl": "https://cdn.contentful.com/spaces/emh6o2ireilu/sync?sync_token=w5ZGw6JFwqZmVcKsE8Kow4grw45QdybCr1IuSMKBHcKNbynCrcOdF8KoNCA_cwJHKx5VfW1EMsOBdkFww5_CjcOMQcOQw4_Dg8KjNcK8w7RrYCY8w57DmjM5wprDgcOxw7JOw7jDuQjDgsKVTsKBw7HDvcOX"
91 | }
92 |
--------------------------------------------------------------------------------
/Tests/Data/SyncTests/initial.json:
--------------------------------------------------------------------------------
1 | {
2 | "sys": {
3 | "type": "Array"
4 | },
5 | "items": [
6 | {
7 | "fields": {
8 | "title": {
9 | "en-US": "contentful-logo"
10 | },
11 | "file": {
12 | "en-US": {
13 | "fileName": "512_black.png",
14 | "contentType": "image/png",
15 | "details": {
16 | "image": {
17 | "width": 512,
18 | "height": 512
19 | },
20 | "size": 4189
21 | },
22 | "url": "//images.contentful.com/emh6o2ireilu/2q1Ns7Oygo2mAgoweuMCAA/7a4eb574952f359b851b3f353573b708/512_black.png"
23 | }
24 | }
25 | },
26 | "sys": {
27 | "space": {
28 | "sys": {
29 | "type": "Link",
30 | "linkType": "Space",
31 | "id": "emh6o2ireilu"
32 | }
33 | },
34 | "type": "Asset",
35 | "id": "2q1Ns7Oygo2mAgoweuMCAA",
36 | "revision": 1,
37 | "createdAt": "2014-03-25T11:01:41.057Z",
38 | "updatedAt": "2014-03-25T11:01:41.057Z"
39 | }
40 | },
41 | {
42 | "sys": {
43 | "space": {
44 | "sys": {
45 | "type": "Link",
46 | "linkType": "Space",
47 | "id": "emh6o2ireilu"
48 | }
49 | },
50 | "type": "Entry",
51 | "contentType": {
52 | "sys": {
53 | "type": "Link",
54 | "linkType": "ContentType",
55 | "id": "6bAvxqodl6s4MoKuWYkmqe"
56 | }
57 | },
58 | "id": "4upDPGUMMEkG8w8UUs2OiO",
59 | "revision": 1,
60 | "createdAt": "2014-03-25T11:00:43.065Z",
61 | "updatedAt": "2014-03-25T11:00:43.065Z"
62 | },
63 | "fields": {
64 | "title": {
65 | "en-US": "Test"
66 | },
67 | "body": {
68 | "en-US": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
69 | }
70 | }
71 | }
72 | ],
73 | "nextSyncUrl": "https://cdn.contentful.com/spaces/emh6o2ireilu/sync?sync_token=w5ZGw6JFwqZmVcKsE8Kow4grw45QdyYxwoHDtsKywrXDmQs_WcOvIcOzwotYw6PCgcOsAcOYYcO4YsKCw7TCnsK_clnClS7Csx9lwoFcw6nCqnnCpWh3w7k7SkI-CcOuQyXDlw_Dlh9RwqkcElwpW30sw4k"
74 | }
75 |
--------------------------------------------------------------------------------
/Tests/Data/SyncTests/update.json:
--------------------------------------------------------------------------------
1 | {
2 | "sys": {
3 | "type": "Array"
4 | },
5 | "items": [
6 | {
7 | "fields": {
8 | "title": {
9 | "en-US": "doge (changed)"
10 | },
11 | "file": {
12 | "en-US": {
13 | "fileName": "vaa4by0.png",
14 | "contentType": "image/png",
15 | "details": {
16 | "image": {
17 | "width": 265,
18 | "height": 265
19 | },
20 | "size": 103652
21 | },
22 | "url": "//images.contentful.com/emh6o2ireilu/6koKmTXVzUquae6ewQQ8Eu/5f79cef98e3feb466c30f0b38bec0359/vaa4by0.png"
23 | }
24 | }
25 | },
26 | "sys": {
27 | "space": {
28 | "sys": {
29 | "type": "Link",
30 | "linkType": "Space",
31 | "id": "emh6o2ireilu"
32 | }
33 | },
34 | "type": "Asset",
35 | "id": "6koKmTXVzUquae6ewQQ8Eu",
36 | "revision": 2,
37 | "createdAt": "2014-03-25T11:08:25.412Z",
38 | "updatedAt": "2014-03-26T10:37:20.069Z"
39 | }
40 | },
41 | {
42 | "sys": {
43 | "space": {
44 | "sys": {
45 | "type": "Link",
46 | "linkType": "Space",
47 | "id": "emh6o2ireilu"
48 | }
49 | },
50 | "type": "Entry",
51 | "contentType": {
52 | "sys": {
53 | "type": "Link",
54 | "linkType": "ContentType",
55 | "id": "6bAvxqodl6s4MoKuWYkmqe"
56 | }
57 | },
58 | "id": "4upDPGUMMEkG8w8UUs2OiO",
59 | "revision": 2,
60 | "createdAt": "2014-03-25T11:00:43.065Z",
61 | "updatedAt": "2014-03-26T10:37:09.128Z"
62 | },
63 | "fields": {
64 | "title": {
65 | "en-US": "Test (changed)"
66 | },
67 | "body": {
68 | "en-US": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
69 | }
70 | }
71 | }
72 | ],
73 | "nextSyncUrl": "https://cdn.contentful.com/spaces/emh6o2ireilu/sync?sync_token=w5ZGw6JFwqZmVcKsE8Kow4grw45QdybCvMKEwp1eHxbDvzpAw5BOfcOEwqNMw4LChcKHwpBYw5FsHGMddMKsCBrChcKiOcKoG3ICUz8-C8K9TcOvQcO7wodaw5kVwpLCgx1kw7M7w4xVwoRswrpIwpsmw58"
74 | }
75 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/CDAConfiguration.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDAConfiguration.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 04/03/14.
6 | //
7 | //
8 |
9 | #if __has_feature(modules)
10 | @import Foundation;
11 | #else
12 | #import
13 | #endif
14 |
15 | #import "CDANullabilityStubs.h"
16 |
17 | NS_ASSUME_NONNULL_BEGIN
18 |
19 | extern const NSString* const CDA_DEFAULT_SERVER;
20 |
21 | /**
22 | Class representing additional configuration options for a `CDAClient`.
23 | */
24 | @interface CDAConfiguration : NSObject
25 |
26 | /** @name Creating a configuration */
27 |
28 | /**
29 | * Creating a configuration with default parameters.
30 | *
31 | * @return A configuration initialized with default parameters.
32 | */
33 | +(instancetype)defaultConfiguration;
34 |
35 | /** @name Configuring parameters */
36 |
37 | /** Automatically filter any non-existing resources being linked to. */
38 | @property (nonatomic) BOOL filterNonExistingResources;
39 |
40 | /** Automatically retry requests if rate-limits are exceeded. */
41 | @property (nonatomic) BOOL rateLimiting;
42 |
43 | /** If `YES`, a secure HTTPS connection will be used instead of regular HTTP. Default value: `YES` */
44 | @property (nonatomic) BOOL secure;
45 |
46 | /** The server address to use for accessing any resources. Default value: "cdn.contentful.com" */
47 | @property (nonatomic) NSString* server;
48 |
49 | /** @name Configure Preview Mode */
50 |
51 | /** Preview mode allows retrieving unpublished Resources.
52 |
53 | To use it, you have to obtain a special access
54 | token which you can get in the "API" tab of the Contentful app.
55 |
56 | In preview mode, data can be invalid, because no validation is performed on unpublished entries. Your
57 | app needs to deal with that. Be aware that the access token is read-write and should in no case be
58 | shipped with a production app.
59 |
60 | Another difference in preview mode is that there are never any updates when performing
61 | synchronizations. You will receive all Assets and Entries during the initial synchronization, just as
62 | in normal mode, including the unpublished Resources. Any subsequent synchronization will return
63 | successful immediately, not reporting any changes. In addition to that, the parameters for syncing
64 | specific content will have no effect in preview mode, instead all content will always be fetched.
65 |
66 | In preview mode, the `include` parameter of a query is not used at all, instead includes will always
67 | be resolved for full ten levels. Because of this, preview mode will be slower than normal.
68 | */
69 | @property (nonatomic) BOOL previewMode;
70 |
71 | @end
72 |
73 | NS_ASSUME_NONNULL_END
74 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/CDAField.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDAField.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 04/03/14.
6 | //
7 | //
8 |
9 | #if __has_feature(modules)
10 | @import Foundation;
11 | #else
12 | #import
13 | #endif
14 |
15 | #import "CDANullabilityStubs.h"
16 |
17 | /**
18 | Possible field types.
19 |
20 | [For further reference](https://www.contentful.com/developers/documentation/content-delivery-api/#content-type-fields)
21 | */
22 | typedef NS_ENUM(NSInteger, CDAFieldType) {
23 | /** List of values. Value type depends on `itemType` property. */
24 | CDAFieldTypeArray,
25 | /** Flag, represented as a `BOOL`. */
26 | CDAFieldTypeBoolean,
27 | /** Date, represented as an `NSDate` instance. */
28 | CDAFieldTypeDate,
29 | /** Number type without decimals. Values from -2^53 to 2^53. */
30 | CDAFieldTypeInteger,
31 | /** Links represent relationships between Resources. */
32 | CDAFieldTypeLink,
33 | /** A location coordinate, values should be retrieved using the `-CLLocationCoordinate2DFromFieldWithIdentifier:` of `CDAEntry`. */
34 | CDAFieldTypeLocation,
35 | /** Unspecified, used to denominate the `itemType` of any field which is not an array. */
36 | CDAFieldTypeNone,
37 | /** Number type with decimals. */
38 | CDAFieldTypeNumber,
39 | /** JSON object. */
40 | CDAFieldTypeObject,
41 | /** Basic list of characters. */
42 | CDAFieldTypeSymbol,
43 | /** Same as String, but can be filtered via [Full-Text Search](https://www.contentful.com/developers/documentation/content-delivery-api/#search-filter-full-text). */
44 | CDAFieldTypeText,
45 | /** Used as `itemType` for arrays of entries or as `type` for links. */
46 | CDAFieldTypeEntry,
47 | /** Used as `itemType` for arrays of assets or as `type` for links. */
48 | CDAFieldTypeAsset,
49 | };
50 |
51 | NS_ASSUME_NONNULL_BEGIN
52 |
53 | /** A `CDAField` describes a single property of a `CDAEntry`. */
54 | @interface CDAField : NSObject
55 |
56 | /** @name Accessing Field Information */
57 |
58 | /** Unique ID of the field. */
59 | @property (nonatomic, readonly) NSString* identifier;
60 | /** Name of the field. */
61 | @property (nonatomic, readonly) NSString* name;
62 | /** Type of the field. */
63 | @property (nonatomic, readonly) CDAFieldType type;
64 | /** Whether the field was disabled. */
65 | @property (nonatomic, readonly) BOOL disabled;
66 |
67 | /** @name Accessing the Type of Array Items */
68 |
69 | /** Field type of items if the field is an Array, `CDAFieldTypeNone` otherwise. */
70 | @property (nonatomic, readonly) CDAFieldType itemType;
71 |
72 | @end
73 |
74 | NS_ASSUME_NONNULL_END
75 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | __SIM_ID=`xcrun simctl list|egrep -m 1 '$(SIM_NAME) \([^(]*\) \([^(]*\)$$'|sed -e 's/.* (\(.*\)) (.*)/\1/'`
2 | SIM_NAME=iPhone 6s
3 | SIM_ID=$(shell echo $(__SIM_ID))
4 |
5 | ifeq ($(strip $(SIM_ID)),)
6 | $(error Could not find $(SIM_NAME) simulator)
7 | endif
8 |
9 | WORKSPACE=ContentfulSDK.xcworkspace
10 |
11 | .PHONY: all open clean clean_simulators clean_pods doc example example-static pod static-lib test kill_simulator docs
12 |
13 | open:
14 | open ContentfulSDK.xcworkspace
15 |
16 | clean_pods:
17 | rm -rf Pods/
18 |
19 | clean: clean_simulators
20 | rm -rf $(HOME)/Library/Developer/Xcode/DerivedData/*
21 |
22 | clean_simulators: kill_simulator
23 | xcrun simctl erase all
24 |
25 | all: test example_static
26 |
27 | pod:
28 | bundle exec pod install
29 | xcversion select 7.3.1
30 | xcrun bitcode_strip -r Pods/Realm/core/librealm-ios.a -o Pods/Realm/core/librealm-ios.a
31 |
32 | example:
33 | set -o pipefail && xcodebuild clean build -workspace $(WORKSPACE) \
34 | -scheme ContentfulDeliveryAPI \
35 | -sdk iphonesimulator -destination 'id=$(SIM_ID)'| xcpretty -c
36 | set -o pipefail && xcodebuild clean build -workspace $(WORKSPACE) \
37 | -scheme 'UFO Example' \
38 | -sdk iphonesimulator -destination 'id=$(SIM_ID)'| xcpretty -c
39 |
40 | example_static: static_lib
41 | cd Examples/UFO; set -o pipefail && xcodebuild clean build \
42 | -sdk iphonesimulator -destination 'id=$(SIM_ID)'| xcpretty -c
43 |
44 | static_lib:
45 | bundle exec pod repo update >/dev/null
46 | bundle exec pod package ContentfulDeliveryAPI.podspec
47 |
48 | @cd Examples/UFO/Distribution; ./update.sh
49 | cd Examples; ./ship_it.sh
50 |
51 | rm -rf ContentfulDeliveryAPI-*/
52 |
53 | kill_simulator:
54 | killall "Simulator" || true
55 |
56 | cda: clean_simulators
57 | set -x -o pipefail && xcodebuild -jobs `sysctl -n hw.ncpu` test -workspace $(WORKSPACE) \
58 | -scheme 'ContentfulDeliveryAPI' -sdk iphonesimulator \
59 | -destination 'platform=iOS Simulator,name=iPhone 6s,OS=11.4'| xcpretty -c
60 | kill_simulator
61 | bundle exec pod lib coverage
62 |
63 | integration_test: really_clean clean_simulators
64 | set -x -o pipefail && xcodebuild test -workspace $(WORKSPACE) \
65 | -scheme 'ContentfulDeliveryAPI' -configuration "API_Coverage" \
66 | -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6s,OS=9.3' | xcpretty -c
67 |
68 | lint:
69 | set -o pipefail && xcodebuild clean build -workspace $(WORKSPACE) -dry-run \
70 | -scheme ContentfulDeliveryAPI \
71 | -sdk iphonesimulator -destination 'id=$(SIM_ID)' clean build| \
72 | xcpretty -r json-compilation-database -o compile_commands.json
73 | oclint-json-compilation-database
74 |
75 | docs:
76 | ./scripts/reference-docs.sh
77 |
78 |
79 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/CDAClient+Private.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDAClient.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 04/03/14.
6 | //
7 | //
8 |
9 | #import "CDAClient.h"
10 |
11 | @class CDAContentTypeRegistry;
12 | @class CDARequestOperationManager;
13 |
14 | extern NSString* const CDAContentTypeHeader;
15 | extern NSString* const CMAContentTypeHeader;
16 |
17 | @interface CDAClient ()
18 |
19 | @property (nonatomic, readonly) BOOL localizationAvailable;
20 | @property (nonatomic, readonly) NSString* protocol;
21 | @property (nonatomic) CDARequestOperationManager* requestOperationManager;
22 | @property (nonatomic) NSString* resourceClassPrefix;
23 |
24 | -(instancetype)initWithSpaceKey:(NSString *)spaceKey
25 | accessToken:(NSString *)accessToken
26 | configuration:(CDAConfiguration*)configuration
27 | isCMARequest:(BOOL)isCMARequest;
28 |
29 | -(CDAConfiguration*)configuration;
30 | -(instancetype)copyWithSpace:(CDASpace*)space;
31 | -(CDAContentTypeRegistry*)contentTypeRegistry;
32 | -(CDARequest*)deleteURLPath:(NSString*)URLPath
33 | headers:(NSDictionary*)headers
34 | parameters:(NSDictionary*)parameters
35 | success:(CDAObjectFetchedBlock)success
36 | failure:(CDARequestFailureBlock)failure;
37 | -(CDARequest*)fetchArrayAtURLPath:(NSString *)URLPath
38 | parameters:(NSDictionary *)parameters
39 | success:(CDAArrayFetchedBlock)success
40 | failure:(CDARequestFailureBlock)failure;
41 | -(CDAArray*)fetchAssetsMatching:(NSDictionary*)query synchronouslyWithError:(NSError**)error;
42 | -(CDAArray*)fetchContentTypesMatching:(NSDictionary*)query synchronouslyWithError:(NSError**)error;
43 | -(CDAArray*)fetchEntriesMatching:(NSDictionary*)query synchronouslyWithError:(NSError**)error;
44 | -(CDARequest*)fetchURLPath:(NSString*)URLPath
45 | parameters:(NSDictionary*)parameters
46 | success:(CDAObjectFetchedBlock)success
47 | failure:(CDARequestFailureBlock)failure;
48 | -(CDARequest*)postURLPath:(NSString*)URLPath
49 | headers:(NSDictionary*)headers
50 | parameters:(NSDictionary*)parameters
51 | success:(CDAObjectFetchedBlock)success
52 | failure:(CDARequestFailureBlock)failure;
53 | -(CDARequest*)putURLPath:(NSString*)URLPath
54 | headers:(NSDictionary*)headers
55 | parameters:(NSDictionary*)parameters
56 | success:(CDAObjectFetchedBlock)success
57 | failure:(CDARequestFailureBlock)failure;
58 | -(CDASpace*)space;
59 | -(NSString*)spaceKey;
60 |
61 | @end
62 |
--------------------------------------------------------------------------------
/Tests/LocalizedModel.xcdatamodeld/LocalizedModel.xcdatamodel/contents:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/Resources/CDAEntry.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDAEntry.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 04/03/14.
6 | //
7 | //
8 |
9 | #if __has_feature(modules)
10 | @import MapKit;
11 | #else
12 | #import "
13 | #endif
14 |
15 | #import "CDANullabilityStubs.h"
16 | #import "CDAResource.h"
17 |
18 | @class CDAContentType;
19 |
20 | NS_ASSUME_NONNULL_BEGIN
21 |
22 | /**
23 | Entries represent textual content in a Space. An Entry's data adheres to a certain Content Type.
24 | */
25 | @interface CDAEntry : CDAResource
26 |
27 | /** @name Accessing Fields */
28 |
29 | /** Properties according to Content Type. */
30 | @property (nonatomic, readonly) NSDictionary* fields;
31 |
32 | /**
33 | Retrieve the value of a specific Field as a `CLLocationCoordinate2D` for easy interaction with
34 | CoreLocation or MapKit.
35 |
36 | @param identifier The `sys.id` of the Field which should be queried.
37 | @return The actual location value of the Field.
38 | @exception NSIllegalArgumentException If the specified Field is not of type Location.
39 | */
40 | -(CLLocationCoordinate2D)CLLocationCoordinate2DFromFieldWithIdentifier:(NSString*)identifier;
41 |
42 | /** @name Accessing Content Types */
43 |
44 | /** The Entry's Content Type. */
45 | @property (nonatomic, readonly) CDAContentType* __nullable contentType;
46 |
47 | /** @name Accessing Localized Content */
48 |
49 | /**
50 | * Locale to be used for accessing any values of `fields`.
51 | *
52 | * By default, this will be set to the Space's default locale. If set to a non-existing locale, it
53 | * will automatically revert to the default value.
54 | *
55 | * Changing this property only has an effect if the receiver was obtained from a `CDASyncedSpace`
56 | * originally. Entries obtained any other way will only contain values for the locale specified in
57 | * the query or for the default locale. In addition to that, this properties value will also only
58 | * be accurate for Entries obtained from a `CDASyncedSpace`originally.
59 | *
60 | */
61 | @property (nonatomic) NSString* locale;
62 |
63 | /** @name Handle custom objects */
64 |
65 | /**
66 | * Copy a set of Field values from this Entry to any custom object you provide. The mapping is
67 | * supposed to map a keypath on this Entry to a keypath on `object`.
68 | *
69 | * This can be used as a quick way to fill your own value objects with data from Entries fetched
70 | * from the Contentful API, e.g. if you want to use Core Data in your app.
71 | *
72 | * Currently, this method does no conversion or error checking on top of what is already provided by
73 | * Key-Value-Coding. However, it will skip all relations to other Resources, because those will
74 | * likely need special behaviour.
75 | *
76 | * Example:
77 | *
78 | * `[someEntry mapFieldsToObject:someObject usingMapping:@{ @"fields.name": @"name" }];
79 | *
80 | * @param object The target object which is supposed to be filled with data.
81 | * @param dictionary A dictionary described the mapping between keypaths on the Entry and
82 | * keypaths on the `object` parameter.
83 | *
84 | * @return To make one line mappings possible, this method returns the `object` parameter.
85 | */
86 | -(id)mapFieldsToObject:(NSObject*)object usingMapping:(NSDictionary*)dictionary;
87 |
88 | @end
89 |
90 | NS_ASSUME_NONNULL_END
91 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/CDARequestSerializer.m:
--------------------------------------------------------------------------------
1 |
2 | //
3 | // CDARequestSerializer.m
4 | // ContentfulSDK
5 | //
6 | // Created by Boris Bügling on 21/07/14.
7 | //
8 | //
9 |
10 | #import "CDARequestSerializer.h"
11 | #import "CDAUtilities.h"
12 | #import "Versions.h"
13 |
14 | @implementation CDARequestSerializer
15 |
16 | -(instancetype)initWithAccessToken:(NSString*)accessToken {
17 | NSParameterAssert(accessToken);
18 |
19 | self = [super init];
20 | if (self) {
21 | [self setValue:[@"Bearer " stringByAppendingString:accessToken] forHTTPHeaderField:@"Authorization"];
22 |
23 | NSString *userAgentHeaderString = [self userAgentHeaderString];
24 | [self setValue:userAgentHeaderString forHTTPHeaderField:@"X-Contentful-User-Agent"];
25 | }
26 | return self;
27 | }
28 |
29 | - (NSString *)userAgentHeaderString {
30 | NSMutableString *userAgentString = [[NSMutableString alloc] initWithString:@""];
31 |
32 | NSString *appVersionString = [self appVersionString];
33 | if (appVersionString != nil) {
34 | [userAgentString appendString:[NSString stringWithFormat:@"app %@; ", appVersionString]];
35 | }
36 |
37 | [userAgentString appendString:[NSString stringWithFormat:@"sdk %@;", [self sdkVersionString]]];
38 | [userAgentString appendString:[NSString stringWithFormat:@" platform %@;", [self platformVersionString]]];
39 |
40 | NSString *operatingSystemVersionString = [self operatingSystemVersionString];
41 | if (operatingSystemVersionString != nil) {
42 | [userAgentString appendString:[NSString stringWithFormat:@" os %@;", operatingSystemVersionString]];
43 | }
44 | return userAgentString;
45 | }
46 |
47 | - (NSString *)appVersionString {
48 | NSDictionary *bundleInfo = [[NSBundle mainBundle] infoDictionary];
49 | NSString *versionNumberString = bundleInfo[@"CFBundleShortVersionString"];
50 | NSString *appBundleId = [[NSBundle mainBundle] bundleIdentifier];
51 | if (versionNumberString == nil || appBundleId == nil) {
52 | return nil;
53 | }
54 |
55 | return [NSString stringWithFormat:@"%@/%@", appBundleId, versionNumberString];
56 | }
57 |
58 | - (NSString *)platformVersionString {
59 | return @"Objective-C";
60 | }
61 |
62 | - (NSString *)sdkVersionString {
63 |
64 | NSString *sdkVersion = DELIVERY_SDK_VERSION;
65 | NSString *sdkVersionString = [NSString stringWithFormat:@"contentful.objc/%@", sdkVersion];
66 |
67 | return sdkVersionString;
68 | }
69 |
70 | - (NSString *)operatingSystemVersionString {
71 | NSString *operatingSystemPlatform = [self operatingSystemPlatform];
72 | if (operatingSystemPlatform == nil) {
73 | return nil;
74 | }
75 |
76 | NSOperatingSystemVersion osVersion = [[NSProcessInfo processInfo] operatingSystemVersion];
77 | NSString *osVersionString = [NSString stringWithFormat:@"%li.%li.%li", (long)osVersion.majorVersion, (long)osVersion.minorVersion, (long)osVersion.patchVersion];
78 |
79 | return [NSString stringWithFormat:@"%@/%@", operatingSystemPlatform, osVersionString];
80 | }
81 |
82 |
83 | - (NSString *)operatingSystemPlatform {
84 | NSString *osName;
85 |
86 | #if TARGET_OS_IOS
87 | osName = @"iOS";
88 | #elif TARGET_OS_OSX
89 | osName = @"macOS";
90 | #elif TARGET_OS_TV
91 | osName = @"tvOS";
92 | #elif TARGET_OS_WATCH
93 | osName = @"watchOS";
94 | #endif
95 | return osName;
96 | }
97 |
98 | @end
99 |
--------------------------------------------------------------------------------
/Tests/LinkedAssetSyncTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // LinkedAssetSyncTest.m
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 09/04/14.
6 | //
7 | //
8 |
9 | #import "SyncBaseTestCase.h"
10 |
11 | @interface LinkedAssetSyncTest : SyncBaseTestCase
12 |
13 | @end
14 |
15 | #pragma mark -
16 |
17 | @implementation LinkedAssetSyncTest
18 |
19 | -(void)setUp {
20 | [super setUp];
21 |
22 | /*
23 | Map URLs to JSON response files
24 | */
25 | NSDictionary* stubs = @{ @"https://cdn.contentful.com/spaces/emh6o2ireilu/sync?initial=true": @"AssetTestInitial", @"https://cdn.contentful.com/spaces/emh6o2ireilu/sync?sync_token=w5ZGw6JFwqZmVcKsE8Kow4grw45QdyZ7T8Obw5Inwoh6Tk7Cq8KUDcK7w5ssw6vCgjLDjk9Hwr3DusOzw7XCo8OIwo3CicK5SBkqCcK7woDDhSjCkMOGw7rCqMOtE1V1L3LDq8KIck_DssK4K8OBe0vDn0vDrXjDkMOf": @"AssetTestUpdate", @"https://cdn.contentful.com/spaces/emh6o2ireilu/": @"space", @"https://cdn.contentful.com/spaces/emh6o2ireilu/assets?limit=1&sys.id%5Bin%5D=2q1Ns7Oygo2mAgoweuMCAA": @"AssetTestResolve", @"https://cdn.contentful.com/spaces/emh6o2ireilu/entries?limit=1&sys.id%5Bin%5D=6nRlw4CofeeICEYgIqaIIg": @"AssetTestResolve2", };
26 |
27 | [self stubHTTPRequestUsingFixtures:stubs inDirectory:@"ComplexSyncTests"];
28 | }
29 |
30 | -(void)syncedSpace:(CDASyncedSpace *)space didCreateEntry:(CDAEntry *)entry {
31 | [super syncedSpace:space didCreateEntry:entry];
32 |
33 | XCTAssertNotNil([entry.fields[@"picture"] URL], @"");
34 | }
35 |
36 | -(void)testSyncLinkedAsset {
37 | XCTestExpectation *expectation = [self expectationWithDescription:@""];
38 |
39 | CDARequest* request = [self.client initialSynchronizationWithSuccess:^(CDAResponse *response, CDASyncedSpace *space) {
40 | space.delegate = self;
41 |
42 | [space performSynchronizationWithSuccess:^{
43 | [expectation fulfill];
44 | } failure:^(CDAResponse *response, NSError *error) {
45 | XCTFail(@"Error: %@", error);
46 |
47 | [expectation fulfill];
48 | }];
49 | } failure:^(CDAResponse *response, NSError *error) {
50 | XCTFail(@"Error: %@", error);
51 |
52 | [expectation fulfill];
53 | }];
54 | XCTAssertNotNil(request, @"");
55 |
56 | [self waitForExpectationsWithTimeout:10.0 handler:nil];
57 | }
58 |
59 | -(void)testSyncLinkedAssetWithoutSyncSpaceInstance {
60 | XCTestExpectation *expectation = [self expectationWithDescription:@""];
61 |
62 | CDARequest* request = [self.client initialSynchronizationWithSuccess:^(CDAResponse *response, CDASyncedSpace *space) {
63 | CDASyncedSpace* shallowSyncSpace = [CDASyncedSpace shallowSyncSpaceWithToken:space.syncToken
64 | client:self.client];
65 | shallowSyncSpace.delegate = self;
66 |
67 | [shallowSyncSpace performSynchronizationWithSuccess:^{
68 | [expectation fulfill];
69 | } failure:^(CDAResponse *response, NSError *error) {
70 | XCTFail(@"Error: %@", error);
71 |
72 | [expectation fulfill];
73 | }];
74 | } failure:^(CDAResponse *response, NSError *error) {
75 | XCTFail(@"Error: %@", error);
76 |
77 | [expectation fulfill];
78 | }];
79 | XCTAssertNotNil(request, @"");
80 |
81 | [self waitForExpectationsWithTimeout:10.0 handler:nil];
82 | }
83 |
84 | @end
85 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/Resources/CDAResource.h:
--------------------------------------------------------------------------------
1 | //
2 | // CDAResource.h
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 04/03/14.
6 | //
7 | //
8 |
9 | #import "CDANullabilityStubs.h"
10 |
11 | #if __has_feature(modules)
12 | @import Foundation;
13 | #else
14 | #import
15 | #endif
16 |
17 | @class CDAClient;
18 | @class CDAResponse;
19 |
20 | NS_ASSUME_NONNULL_BEGIN
21 |
22 | /** Base class of all remotely available entities. */
23 | @interface CDAResource : NSObject
24 |
25 | /** @name Accessing System Properties */
26 |
27 | /** The `sys.id` of this Resource, used to uniquely identify it in its Space. */
28 | @property (nonatomic, readonly) NSString* identifier;
29 | /** Value of all system properties of this Resource. */
30 | @property (nonatomic, readonly) NSDictionary* sys;
31 |
32 | /** @name Comparing Resources */
33 |
34 | /**
35 | * Returns a Boolean value that indicates whether a given Resource is equal to the receiver.
36 | *
37 | * @param resource The Resource with which to compare the receiver.
38 | *
39 | * @return `YES` if `resource` is equivalent to the receiver, otherwise `NO`.
40 | */
41 | -(BOOL)isEqualToResource:(CDAResource*)resource;
42 |
43 | /** @name Persisting Resources */
44 |
45 | /**
46 | * Read a previously serialized Resource from file.
47 | *
48 | * @param filePath The path to the file with a serialized Resource.
49 | * @param client The client to use for upcoming requests.
50 | *
51 | * @return A new Resource initialized with values from a previously serialized Resource.
52 | */
53 | +(nullable instancetype)readFromFile:(NSString*)filePath client:(CDAClient*)client;
54 |
55 | /**
56 | * Read a previously serialized Resource from file.
57 | *
58 | * @param fileURL The file URL to the file with a serialized Resource.
59 | * @param client The client to use for upcoming requests.
60 | *
61 | * @return A new Resource initialized with values from a previously serialized Resource.
62 | */
63 | +(nullable instancetype)readFromFileURL:(NSURL*)fileURL client:(CDAClient*)client;
64 |
65 | /**
66 | * Serialize a Resource to a file.
67 | *
68 | * This can be used for offline caching of Resources.
69 | *
70 | * @param filePath The path to the file to which the Resource should be written.
71 | */
72 | -(void)writeToFile:(NSString*)filePath;
73 |
74 | /** @name Accessing Remote Data */
75 |
76 | /**
77 | Indicates whether or not the actual data of this Resource has been fetched yet. It will usually have
78 | the value `NO` for linked resources, unless you set `include` in the initial query. You can easily
79 | request the missing data by invoking `resolveWithSuccess:failure:` on it.
80 | */
81 | @property (nonatomic, readonly) BOOL fetched;
82 |
83 | /**
84 | * Resolve a Link by fetching the actual data of the Resource. If the data of the Resource is already
85 | * complete, the `success` block will be called immediately, with `response` being `nil` as no
86 | * additional network requests were made.
87 | *
88 | * @param success A block which gets called upon successful retrieval of all data.
89 | * @param failure A block which gets called if an error occured during the retrieval process.
90 | */
91 | -(void)resolveWithSuccess:(void (^)(CDAResponse* response, CDAResource* resource))success
92 | failure:(void (^)(CDAResponse* response, NSError* error))failure;
93 |
94 | @end
95 |
96 | NS_ASSUME_NONNULL_END
97 |
--------------------------------------------------------------------------------
/Tests/ComplexSyncTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // ComplexSyncTests.m
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 09/04/14.
6 | //
7 | //
8 |
9 | #import "SyncBaseTestCase.h"
10 |
11 | @interface ComplexSyncTests : SyncBaseTestCase
12 |
13 | @end
14 |
15 | #pragma mark -
16 |
17 | @implementation ComplexSyncTests
18 |
19 | -(void)setUp {
20 | [super setUp];
21 |
22 | /*
23 | Map URLs to JSON response files
24 | */
25 | NSDictionary* stubs = @{ @"https://cdn.contentful.com/spaces/emh6o2ireilu/sync?initial=true": @"LinkTestInitial", @"https://cdn.contentful.com/spaces/emh6o2ireilu/sync?sync_token=w5ZGw6JFwqZmVcKsE8Kow4grw45QdyYZw7DCkTbDliYIw4vDp0jCqMOQw7vDqAbCoiLDkAnCs8OWXcOEwpXClGoUWMK1w54KCmlqw48Ow6EaJzQjwrnCnS3DpsKOw57CpMK1wrEGwrV8wpzCmcKtwqbCisK4w5LDgMKYw6HDsQ": @"LinkTestUpdate", @"https://cdn.contentful.com/spaces/emh6o2ireilu/": @"space", @"https://cdn.contentful.com/spaces/emh6o2ireilu/entries?sys.id%5Bin%5D=6nRlw4CofeeICEYgIqaIIg": @"LinkTestResolve", };
26 |
27 | [self stubHTTPRequestUsingFixtures:stubs inDirectory:@"ComplexSyncTests"];
28 | }
29 |
30 | -(void)testSyncWithLinks {
31 | XCTestExpectation *expectation = [self expectationWithDescription:@""];
32 |
33 | CDARequest* request = [self.client initialSynchronizationWithSuccess:^(CDAResponse *response, CDASyncedSpace *space) {
34 | space.delegate = self;
35 |
36 | [space performSynchronizationWithSuccess:^{
37 | [expectation fulfill];
38 | } failure:^(CDAResponse *response, NSError *error) {
39 | XCTFail(@"Error: %@", error);
40 |
41 | [expectation fulfill];
42 | }];
43 | } failure:^(CDAResponse *response, NSError *error) {
44 | XCTFail(@"Error: %@", error);
45 |
46 | [expectation fulfill];
47 | }];
48 | XCTAssertNotNil(request, @"");
49 |
50 | [self waitForExpectationsWithTimeout:10.0 handler:nil];
51 |
52 | XCTAssertEqual(2U, self.numberOfEntriesCreated, @"");
53 | XCTAssertEqual(0U, self.numberOfEntriesUpdated, @"");
54 | }
55 |
56 | -(void)testSyncWithLinksWithoutSyncSpaceInstance {
57 | XCTestExpectation *expectation = [self expectationWithDescription:@""];
58 |
59 | CDARequest* request = [self.client initialSynchronizationWithSuccess:^(CDAResponse *response, CDASyncedSpace *space) {
60 | NSString* syncToken = space.syncToken;
61 | space = nil;
62 | XCTAssertNil(space, @"");
63 |
64 | self.client = [self mockContentTypeRetrievalForClient:[self buildClient]];
65 | CDASyncedSpace* shallowSyncSpace = [CDASyncedSpace shallowSyncSpaceWithToken:syncToken
66 | client:self.client];
67 | shallowSyncSpace.delegate = self;
68 |
69 | [shallowSyncSpace performSynchronizationWithSuccess:^{
70 | [expectation fulfill];
71 | } failure:^(CDAResponse *response, NSError *error) {
72 | XCTFail(@"Error: %@", error);
73 |
74 | [expectation fulfill];
75 | }];
76 | } failure:^(CDAResponse *response, NSError *error) {
77 | XCTFail(@"Error: %@", error);
78 |
79 | [expectation fulfill];
80 | }];
81 | XCTAssertNotNil(request, @"");
82 |
83 | [self waitForExpectationsWithTimeout:10.0 handler:nil];
84 |
85 | XCTAssertEqual(2U, self.numberOfEntriesCreated, @"");
86 | XCTAssertEqual(0U, self.numberOfEntriesUpdated, @"");
87 | }
88 |
89 | @end
90 |
--------------------------------------------------------------------------------
/Tests/Data/ComplexSyncTests/LinkTestInitial.json:
--------------------------------------------------------------------------------
1 | {
2 | "sys": {
3 | "type": "Array"
4 | },
5 | "items": [
6 | {
7 | "sys": {
8 | "space": {
9 | "sys": {
10 | "type": "Link",
11 | "linkType": "Space",
12 | "id": "emh6o2ireilu"
13 | }
14 | },
15 | "type": "Entry",
16 | "contentType": {
17 | "sys": {
18 | "type": "Link",
19 | "linkType": "ContentType",
20 | "id": "51LZmvenywOe8aig28sCgY"
21 | }
22 | },
23 | "id": "1YCXOBW1xu2uSkekCmwyqo",
24 | "revision": 1,
25 | "createdAt": "2014-04-09T11:44:21.359Z",
26 | "updatedAt": "2014-04-09T11:44:21.359Z"
27 | },
28 | "fields": {
29 | "name": {
30 | "en-US": "Some Category"
31 | }
32 | }
33 | },
34 | {
35 | "fields": {
36 | "title": {
37 | "en-US": "doge (changed)"
38 | },
39 | "file": {
40 | "en-US": {
41 | "fileName": "vaa4by0.png",
42 | "contentType": "image/png",
43 | "details": {
44 | "image": {
45 | "width": 265,
46 | "height": 265
47 | },
48 | "size": 103652
49 | },
50 | "url": "//images.contentful.com/emh6o2ireilu/6koKmTXVzUquae6ewQQ8Eu/5f79cef98e3feb466c30f0b38bec0359/vaa4by0.png"
51 | }
52 | }
53 | },
54 | "sys": {
55 | "space": {
56 | "sys": {
57 | "type": "Link",
58 | "linkType": "Space",
59 | "id": "emh6o2ireilu"
60 | }
61 | },
62 | "type": "Asset",
63 | "id": "6koKmTXVzUquae6ewQQ8Eu",
64 | "revision": 2,
65 | "createdAt": "2014-03-25T11:08:25.412Z",
66 | "updatedAt": "2014-03-26T10:37:20.069Z"
67 | }
68 | },
69 | {
70 | "sys": {
71 | "space": {
72 | "sys": {
73 | "type": "Link",
74 | "linkType": "Space",
75 | "id": "emh6o2ireilu"
76 | }
77 | },
78 | "type": "Entry",
79 | "contentType": {
80 | "sys": {
81 | "type": "Link",
82 | "linkType": "ContentType",
83 | "id": "6bAvxqodl6s4MoKuWYkmqe"
84 | }
85 | },
86 | "id": "4upDPGUMMEkG8w8UUs2OiO",
87 | "revision": 2,
88 | "createdAt": "2014-03-25T11:00:43.065Z",
89 | "updatedAt": "2014-03-26T10:37:09.128Z"
90 | },
91 | "fields": {
92 | "title": {
93 | "en-US": "Test (changed)"
94 | },
95 | "body": {
96 | "en-US": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
97 | }
98 | }
99 | }
100 | ],
101 | "nextSyncUrl": "http://cdn.contentful.com/spaces/emh6o2ireilu/sync?sync_token=w5ZGw6JFwqZmVcKsE8Kow4grw45QdyYZw7DCkTbDliYIw4vDp0jCqMOQw7vDqAbCoiLDkAnCs8OWXcOEwpXClGoUWMK1w54KCmlqw48Ow6EaJzQjwrnCnS3DpsKOw57CpMK1wrEGwrV8wpzCmcKtwqbCisK4w5LDgMKYw6HDsQ"
102 | }
103 |
--------------------------------------------------------------------------------
/Tests/Data/ComplexSyncTests/ComplexLinkTestEntries.json:
--------------------------------------------------------------------------------
1 | {
2 | "sys": {
3 | "type": "Array"
4 | },
5 | "total": 2,
6 | "skip": 0,
7 | "limit": 100,
8 | "items": [
9 | {
10 | "sys": {
11 | "space": {
12 | "sys": {
13 | "type": "Link",
14 | "linkType": "Space",
15 | "id": "emh6o2ireilu"
16 | }
17 | },
18 | "type": "Entry",
19 | "contentType": {
20 | "sys": {
21 | "type": "Link",
22 | "linkType": "ContentType",
23 | "id": "6bAvxqodl6s4MoKuWYkmqe"
24 | }
25 | },
26 | "id": "4upDPGUMMEkG8w8UUs2OiO",
27 | "revision": 2,
28 | "createdAt": "2014-03-25T11:00:43.065Z",
29 | "updatedAt": "2014-03-26T10:37:09.128Z",
30 | "locale": "en-US"
31 | },
32 | "fields": {
33 | "title": "Test (changed)",
34 | "body": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
35 | }
36 | },
37 | {
38 | "sys": {
39 | "space": {
40 | "sys": {
41 | "type": "Link",
42 | "linkType": "Space",
43 | "id": "emh6o2ireilu"
44 | }
45 | },
46 | "type": "Entry",
47 | "contentType": {
48 | "sys": {
49 | "type": "Link",
50 | "linkType": "ContentType",
51 | "id": "6bAvxqodl6s4MoKuWYkmqe"
52 | }
53 | },
54 | "id": "1Wl5HnguK8CiaykiQAiGu6",
55 | "revision": 3,
56 | "createdAt": "2014-04-09T11:48:47.866Z",
57 | "updatedAt": "2014-04-10T09:36:40.283Z",
58 | "locale": "en-US"
59 | },
60 | "fields": {
61 | "title": "WithCategory",
62 | "body": "some text",
63 | "category": null,
64 | "picture": {
65 | "sys": {
66 | "type": "Link",
67 | "linkType": "Asset",
68 | "id": "2q1Ns7Oygo2mAgoweuMCAA"
69 | }
70 | }
71 | }
72 | }
73 | ],
74 | "includes": {
75 | "Asset": [
76 | {
77 | "fields": {
78 | "title": "contentful-logo",
79 | "file": {
80 | "fileName": "512_black.png",
81 | "contentType": "image/png",
82 | "details": {
83 | "image": {
84 | "width": 512,
85 | "height": 512
86 | },
87 | "size": 4189
88 | },
89 | "url": "//images.contentful.com/emh6o2ireilu/2q1Ns7Oygo2mAgoweuMCAA/7a4eb574952f359b851b3f353573b708/512_black.png"
90 | }
91 | },
92 | "sys": {
93 | "space": {
94 | "sys": {
95 | "type": "Link",
96 | "linkType": "Space",
97 | "id": "emh6o2ireilu"
98 | }
99 | },
100 | "type": "Asset",
101 | "id": "2q1Ns7Oygo2mAgoweuMCAA",
102 | "revision": 2,
103 | "createdAt": "2014-03-25T11:01:41.057Z",
104 | "updatedAt": "2014-04-10T08:46:27.961Z",
105 | "locale": "en-US"
106 | }
107 | }
108 | ]
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/Tests/Data/ComplexSyncTests/ComplexLinkTestContentTypes.json:
--------------------------------------------------------------------------------
1 | {
2 | "sys": {
3 | "type": "Array"
4 | },
5 | "total": 2,
6 | "skip": 0,
7 | "limit": 100,
8 | "items": [
9 | {
10 | "sys": {
11 | "space": {
12 | "sys": {
13 | "type": "Link",
14 | "linkType": "Space",
15 | "id": "emh6o2ireilu"
16 | }
17 | },
18 | "type": "Entry",
19 | "contentType": {
20 | "sys": {
21 | "type": "Link",
22 | "linkType": "ContentType",
23 | "id": "6bAvxqodl6s4MoKuWYkmqe"
24 | }
25 | },
26 | "id": "4upDPGUMMEkG8w8UUs2OiO",
27 | "revision": 2,
28 | "createdAt": "2014-03-25T11:00:43.065Z",
29 | "updatedAt": "2014-03-26T10:37:09.128Z",
30 | "locale": "en-US"
31 | },
32 | "fields": {
33 | "title": "Test (changed)",
34 | "body": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
35 | }
36 | },
37 | {
38 | "sys": {
39 | "space": {
40 | "sys": {
41 | "type": "Link",
42 | "linkType": "Space",
43 | "id": "emh6o2ireilu"
44 | }
45 | },
46 | "type": "Entry",
47 | "contentType": {
48 | "sys": {
49 | "type": "Link",
50 | "linkType": "ContentType",
51 | "id": "6bAvxqodl6s4MoKuWYkmqe"
52 | }
53 | },
54 | "id": "1Wl5HnguK8CiaykiQAiGu6",
55 | "revision": 3,
56 | "createdAt": "2014-04-09T11:48:47.866Z",
57 | "updatedAt": "2014-04-10T09:36:40.283Z",
58 | "locale": "en-US"
59 | },
60 | "fields": {
61 | "title": "WithCategory",
62 | "body": "some text",
63 | "category": null,
64 | "picture": {
65 | "sys": {
66 | "type": "Link",
67 | "linkType": "Asset",
68 | "id": "2q1Ns7Oygo2mAgoweuMCAA"
69 | }
70 | }
71 | }
72 | }
73 | ],
74 | "includes": {
75 | "Asset": [
76 | {
77 | "fields": {
78 | "title": "contentful-logo",
79 | "file": {
80 | "fileName": "512_black.png",
81 | "contentType": "image/png",
82 | "details": {
83 | "image": {
84 | "width": 512,
85 | "height": 512
86 | },
87 | "size": 4189
88 | },
89 | "url": "//images.contentful.com/emh6o2ireilu/2q1Ns7Oygo2mAgoweuMCAA/7a4eb574952f359b851b3f353573b708/512_black.png"
90 | }
91 | },
92 | "sys": {
93 | "space": {
94 | "sys": {
95 | "type": "Link",
96 | "linkType": "Space",
97 | "id": "emh6o2ireilu"
98 | }
99 | },
100 | "type": "Asset",
101 | "id": "2q1Ns7Oygo2mAgoweuMCAA",
102 | "revision": 2,
103 | "createdAt": "2014-03-25T11:01:41.057Z",
104 | "updatedAt": "2014-04-10T08:46:27.961Z",
105 | "locale": "en-US"
106 | }
107 | }
108 | ]
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/Tests/NewEntryAndDeletionSyncTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // NewEntryAndDeletionSyncTest.m
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 10/04/14.
6 | //
7 | //
8 |
9 | #import "SyncBaseTestCase.h"
10 |
11 | @interface NewEntryAndDeletionSyncTest : SyncBaseTestCase
12 |
13 | @end
14 |
15 | #pragma mark -
16 |
17 | @implementation NewEntryAndDeletionSyncTest
18 |
19 | -(void)setUp {
20 | [super setUp];
21 |
22 | /*
23 | Map URLs to JSON response files
24 | */
25 | NSDictionary* stubs = @{ @"https://cdn.contentful.com/spaces/emh6o2ireilu/sync?initial=true": @"NewEntryAndDeletionInitial", @"https://cdn.contentful.com/spaces/emh6o2ireilu/sync?sync_token=w5ZGw6JFwqZmVcKsE8Kow4grw45QdybDjMOhw7gcw7BNwqzCqSDDhhrCjcKqWEDCjMKHwp4RE2ROw73ChnJnc3MVwpTCgcOcEMOxw53CpgbCpSXCocKbCBVHF8Kyw5nDmUIKwrnDpVByw4l5w57DvV4swoTCuxPCnQ": @"NewEntryAndDeletionUpdate", @"https://cdn.contentful.com/spaces/emh6o2ireilu/": @"space", @"https://cdn.contentful.com/spaces/emh6o2ireilu/assets?limit=1&sys.id%5Bin%5D=2q1Ns7Oygo2mAgoweuMCAA": @"NewEntryAndDeletionResolve", @"https://cdn.contentful.com/spaces/emh6o2ireilu/entries?limit=1&sys.id%5Bin%5D=6nRlw4CofeeICEYgIqaIIg": @"NewEntryAndDeletionResolve2", };
26 |
27 | [self stubHTTPRequestUsingFixtures:stubs inDirectory:@"ComplexSyncTests"];
28 | }
29 |
30 | -(void)testSyncNewEntryAndDeletion {
31 | XCTestExpectation *expectation = [self expectationWithDescription:@""];
32 |
33 | CDARequest* request = [self.client initialSynchronizationWithSuccess:^(CDAResponse *response, CDASyncedSpace *space) {
34 | space.delegate = self;
35 |
36 | [space performSynchronizationWithSuccess:^{
37 | [expectation fulfill];
38 | } failure:^(CDAResponse *response, NSError *error) {
39 | XCTFail(@"Error: %@", error);
40 |
41 | [expectation fulfill];
42 | }];
43 | } failure:^(CDAResponse *response, NSError *error) {
44 | XCTFail(@"Error: %@", error);
45 |
46 | [expectation fulfill];
47 | }];
48 | XCTAssertNotNil(request, @"");
49 |
50 | [self waitForExpectationsWithTimeout:10.0 handler:nil];
51 |
52 | XCTAssertEqual(1U, self.numberOfEntriesCreated, @"");
53 | XCTAssertEqual(1U, self.numberOfEntriesUpdated, @"");
54 | }
55 |
56 | -(void)testSyncNewEntryAndDeletionWithoutSyncSpaceInstance {
57 | XCTestExpectation *expectation = [self expectationWithDescription:@""];
58 |
59 | CDARequest* request = [self.client initialSynchronizationWithSuccess:^(CDAResponse *response, CDASyncedSpace *space) {
60 | CDASyncedSpace* shallowSyncSpace = [CDASyncedSpace shallowSyncSpaceWithToken:space.syncToken
61 | client:self.client];
62 | shallowSyncSpace.delegate = self;
63 | shallowSyncSpace.lastSyncTimestamp = space.lastSyncTimestamp;
64 |
65 | [shallowSyncSpace performSynchronizationWithSuccess:^{
66 | [expectation fulfill];
67 | } failure:^(CDAResponse *response, NSError *error) {
68 | XCTFail(@"Error: %@", error);
69 |
70 | [expectation fulfill];
71 | }];
72 | } failure:^(CDAResponse *response, NSError *error) {
73 | XCTFail(@"Error: %@", error);
74 |
75 | [expectation fulfill];
76 | }];
77 | XCTAssertNotNil(request, @"");
78 |
79 | [self waitForExpectationsWithTimeout:10.0 handler:nil];
80 |
81 | XCTAssertEqual(1U, self.numberOfEntriesCreated, @"");
82 | XCTAssertEqual(1U, self.numberOfEntriesUpdated, @"");
83 | }
84 |
85 | @end
86 |
--------------------------------------------------------------------------------
/ContentfulSDK.xcodeproj/xcshareddata/xcschemes/CoreDataExample.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/ContentfulSDK.xcodeproj/xcshareddata/xcschemes/DeliveryTests.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
49 |
50 |
51 |
52 |
53 |
54 |
64 |
65 |
68 |
69 |
70 |
71 |
75 |
76 |
77 |
78 |
79 |
80 |
86 |
87 |
89 |
90 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/Tests/Data/SyncTests/all-content-types.json:
--------------------------------------------------------------------------------
1 | {
2 | "sys": {
3 | "type": "Array"
4 | },
5 | "total": 4,
6 | "skip": 0,
7 | "limit": 100,
8 | "items": [
9 | {
10 | "fields": [
11 | {
12 | "name": "link1",
13 | "id": "link1",
14 | "type": "Link",
15 | "linkType": "Entry"
16 | },
17 | {
18 | "name": "link2",
19 | "id": "link2",
20 | "type": "Link",
21 | "linkType": "Entry"
22 | },
23 | {
24 | "name": "link3",
25 | "id": "link3",
26 | "type": "Link",
27 | "linkType": "Entry"
28 | }
29 | ],
30 | "name": "ThreeLinks to other Entries",
31 | "sys": {
32 | "space": {
33 | "sys": {
34 | "type": "Link",
35 | "linkType": "Space",
36 | "id": "emh6o2ireilu"
37 | }
38 | },
39 | "type": "ContentType",
40 | "id": "4yCmJfmk1WeqACagaemOIs",
41 | "revision": 1,
42 | "createdAt": "2014-04-11T11:38:32.120Z",
43 | "updatedAt": "2014-04-11T11:38:32.120Z"
44 | }
45 | },
46 | {
47 | "fields": [
48 | {
49 | "name": "Title",
50 | "id": "title",
51 | "type": "Symbol",
52 | "required": true
53 | },
54 | {
55 | "name": "Body",
56 | "id": "body",
57 | "type": "Text",
58 | "required": true
59 | },
60 | {
61 | "name": "Picture",
62 | "id": "picture",
63 | "type": "Link",
64 | "linkType": "Asset"
65 | },
66 | {
67 | "name": "Category",
68 | "id": "category",
69 | "type": "Link",
70 | "linkType": "Entry"
71 | }
72 | ],
73 | "name": "Blog Post",
74 | "sys": {
75 | "space": {
76 | "sys": {
77 | "type": "Link",
78 | "linkType": "Space",
79 | "id": "emh6o2ireilu"
80 | }
81 | },
82 | "type": "ContentType",
83 | "id": "6bAvxqodl6s4MoKuWYkmqe",
84 | "revision": 3,
85 | "createdAt": "2014-03-25T11:00:11.739Z",
86 | "updatedAt": "2014-04-09T11:48:15.120Z"
87 | },
88 | "displayField": "title"
89 | },
90 | {
91 | "fields": [
92 | {
93 | "name": "such field",
94 | "id": "suchField",
95 | "type": "Symbol"
96 | }
97 | ],
98 | "name": "⚡️ new content type",
99 | "sys": {
100 | "space": {
101 | "sys": {
102 | "type": "Link",
103 | "linkType": "Space",
104 | "id": "emh6o2ireilu"
105 | }
106 | },
107 | "type": "ContentType",
108 | "id": "5kLp8FbRwAG0kcOOYa6GMa",
109 | "revision": 1,
110 | "createdAt": "2014-04-11T08:39:04.421Z",
111 | "updatedAt": "2014-04-11T08:39:04.421Z"
112 | },
113 | "displayField": "suchField"
114 | },
115 | {
116 | "fields": [
117 | {
118 | "name": "Name",
119 | "id": "name",
120 | "type": "Symbol"
121 | }
122 | ],
123 | "name": "Category",
124 | "sys": {
125 | "space": {
126 | "sys": {
127 | "type": "Link",
128 | "linkType": "Space",
129 | "id": "emh6o2ireilu"
130 | }
131 | },
132 | "type": "ContentType",
133 | "id": "51LZmvenywOe8aig28sCgY",
134 | "revision": 1,
135 | "createdAt": "2014-04-09T11:43:50.890Z",
136 | "updatedAt": "2014-04-09T11:43:50.890Z"
137 | },
138 | "displayField": "name"
139 | }
140 | ]
141 | }
142 |
--------------------------------------------------------------------------------
/Tests/SyncSpecificContentTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // SyncSpecificContentTests.m
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 30/04/14.
6 | //
7 | //
8 |
9 | #import "SyncBaseTestCase.h"
10 |
11 | @interface SyncSpecificContentTests : SyncBaseTestCase
12 |
13 | @end
14 |
15 | #pragma mark -
16 |
17 | @implementation SyncSpecificContentTests
18 |
19 | -(void)performSyncTestWithQuery:(NSDictionary*)query
20 | expectedNumberOfAssets:(NSUInteger)numberOfAssets
21 | entries:(NSUInteger)numberOfEntries {
22 | XCTestExpectation *expectation = [self expectationWithDescription:@""];
23 |
24 | [self.client initialSynchronizationMatching:query
25 | success:^(CDAResponse *response, CDASyncedSpace *space) {
26 | XCTAssertEqual(numberOfAssets, space.assets.count, @"");
27 | XCTAssertEqual(numberOfEntries, space.entries.count, @"");
28 |
29 | [expectation fulfill];
30 | } failure:^(CDAResponse *response, NSError *error) {
31 | XCTFail(@"Error: %@", error);
32 |
33 | [expectation fulfill];
34 | }];
35 |
36 | [self waitForExpectationsWithTimeout:10.0 handler:nil];
37 | }
38 |
39 | #pragma mark -
40 |
41 | -(void)testThrowsWhenSpecifyingInvalidQuery {
42 | XCTestExpectation *expectation = [self expectationWithDescription:@""];
43 |
44 | [self.client initialSynchronizationMatching:@{ @"type": @"bar" }
45 | success:^(CDAResponse *response, CDASyncedSpace *space) {
46 | XCTFail(@"This shouldn't be reached.");
47 |
48 | [expectation fulfill];
49 | } failure:^(CDAResponse *response, NSError *error) {
50 | XCTAssertNotNil(error, @"");
51 |
52 | [expectation fulfill];
53 | }];
54 |
55 | [self waitForExpectationsWithTimeout:10.0 handler:nil];
56 | }
57 |
58 | -(void)testSyncAll {
59 | [self performSyncTestWithQuery:@{ @"type": @"all" }
60 | expectedNumberOfAssets:2U
61 | entries:7U];
62 | }
63 |
64 | -(void)testSyncAssets {
65 | [self performSyncTestWithQuery:@{ @"type": @"Asset" }
66 | expectedNumberOfAssets:2U
67 | entries:0U];
68 | }
69 |
70 | -(void)testSyncEntries {
71 | [self performSyncTestWithQuery:@{ @"type": @"Entry" }
72 | expectedNumberOfAssets:0U
73 | entries:7U];
74 | }
75 |
76 | -(void)testSyncEntriesForContentType {
77 | self.client = [CDAClient new];
78 |
79 | [self performSyncTestWithQuery:@{ @"type": @"Entry", @"content_type": @"cat" }
80 | expectedNumberOfAssets:0U
81 | entries:3U];
82 | }
83 |
84 | -(void)testSyncDeletions {
85 | [self performSyncTestWithQuery:@{ @"type": @"Deletion" }
86 | expectedNumberOfAssets:0U
87 | entries:0U];
88 | }
89 |
90 | -(void)testSyncDeletionsOfAssets {
91 | [self performSyncTestWithQuery:@{ @"type": @"DeletedAsset" }
92 | expectedNumberOfAssets:0U
93 | entries:0U];
94 | }
95 |
96 | -(void)testSyncDeletionsOfEntries {
97 | [self performSyncTestWithQuery:@{ @"type": @"DeletedEntry" }
98 | expectedNumberOfAssets:0U
99 | entries:0U];
100 | }
101 |
102 | @end
103 |
--------------------------------------------------------------------------------
/Tests/ClientConfiguration.m:
--------------------------------------------------------------------------------
1 | //
2 | // ClientConfiguration.m
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 01/10/14.
6 | //
7 | //
8 |
9 | #import "ContentfulBaseTestCase.h"
10 |
11 | @interface ClientConfiguration : ContentfulBaseTestCase
12 |
13 | @end
14 |
15 | #pragma mark -
16 |
17 | @implementation ClientConfiguration
18 |
19 | -(void)testClientCanBeInstantiatedWithoutSpaceKey {
20 | CDAClient* client1 = [[CDAClient alloc] initWithSpaceKey:nil accessToken:@"yolo"];
21 | CDAClient* client2 = [[CDAClient alloc] initWithSpaceKey:nil
22 | accessToken:@"yolo"
23 | configuration:[CDAConfiguration defaultConfiguration]];
24 |
25 | XCTAssertNotNil(client1);
26 | XCTAssertNotNil(client2);
27 | }
28 |
29 | -(void)testDefaultUserAgent {
30 | XCTestExpectation *expectation = [self expectationWithDescription:@""];
31 |
32 | CDARequest* request = [self.client fetchEntriesWithSuccess:^(CDAResponse *response,
33 | CDAArray *array) {
34 | [expectation fulfill];
35 | } failure:^(CDAResponse *response, NSError *error) {
36 | [expectation fulfill];
37 | }];
38 |
39 | [self waitForExpectationsWithTimeout:10.0 handler:nil];
40 |
41 | NSString* userAgentString = request.request.allHTTPHeaderFields[@"X-Contentful-User-Agent"];
42 |
43 | NSString *versionNumberRegexString = @"\\d+\\.\\d+\\.\\d+(-(beta|RC|alpha)\\d*)?";
44 |
45 | NSRegularExpression *regex = [[NSRegularExpression alloc] initWithPattern:[NSString stringWithFormat:@"sdk contentful.objc/%@; platform Objective-C; os iOS/\\d+\\.\\d+\\.\\d+;", versionNumberRegexString] options:0 error:nil];
46 | NSArray *matches = [regex matchesInString:userAgentString options:0 range:NSMakeRange(0, userAgentString.length)];
47 |
48 |
49 | XCTAssertTrue(matches.count == 1, @"The user agent header should have had at least one match.");
50 | }
51 |
52 | -(void)testFilterMissingEntities {
53 | CDAConfiguration* configuration = [CDAConfiguration defaultConfiguration];
54 | configuration.filterNonExistingResources = YES;
55 |
56 | self.client = [[CDAClient alloc] initWithSpaceKey:@"vfvjfjyjrbbp"
57 | accessToken:@"422588c021896d2ae01eaf2d68faa720aaf6da4b361e7c99e9afac6feacb498b"
58 | configuration:configuration];
59 |
60 | XCTestExpectation *expectation = [self expectationWithDescription:@""];
61 |
62 | [self.client fetchEntriesWithSuccess:^(CDAResponse* response, CDAArray* array) {
63 | XCTAssertEqual(array.items.count, 1);
64 |
65 | CDAEntry* me = array.items.firstObject;
66 | XCTAssertNil(me.fields[@"link"]);
67 |
68 | [expectation fulfill];
69 | } failure:^(CDAResponse *response, NSError *error) {
70 | XCTFail(@"Error: %@", error);
71 |
72 | [expectation fulfill];
73 | }];
74 |
75 | [self waitForExpectationsWithTimeout:10.0 handler:nil];
76 | }
77 |
78 | -(void)testNotFilterMissingEntitiesIfNotConfigured {
79 | self.client = [[CDAClient alloc] initWithSpaceKey:@"vfvjfjyjrbbp"
80 | accessToken:@"422588c021896d2ae01eaf2d68faa720aaf6da4b361e7c99e9afac6feacb498b"];
81 |
82 | XCTestExpectation *expectation = [self expectationWithDescription:@""];
83 |
84 | [self.client fetchEntriesWithSuccess:^(CDAResponse* response, CDAArray* array) {
85 | XCTAssertEqual(array.items.count, 1);
86 |
87 | CDAEntry* me = array.items.firstObject;
88 | XCTAssertNotNil(me.fields[@"link"]);
89 |
90 | [expectation fulfill];
91 | } failure:^(CDAResponse *response, NSError *error) {
92 | XCTFail(@"Error: %@", error);
93 |
94 | [expectation fulfill];
95 | }];
96 |
97 | [self waitForExpectationsWithTimeout:10.0 handler:nil];
98 | }
99 |
100 | @end
101 |
--------------------------------------------------------------------------------
/ContentfulSDK.xcodeproj/xcshareddata/xcschemes/ContentfulManagementAPI.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
34 |
40 |
41 |
42 |
43 |
44 |
50 |
51 |
52 |
53 |
54 |
55 |
65 |
66 |
72 |
73 |
74 |
75 |
76 |
77 |
83 |
84 |
90 |
91 |
92 |
93 |
95 |
96 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/Resources/CDAContentType.m:
--------------------------------------------------------------------------------
1 | //
2 | // CDAContentType.m
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 04/03/14.
6 | //
7 | //
8 |
9 | #import "CDAContentType.h"
10 |
11 | #import "CDAClient+Private.h"
12 | #import "CDAContentTypeRegistry.h"
13 | #import "CDAField+Private.h"
14 | #import "CDAResource+Private.h"
15 |
16 | @interface CDAContentType ()
17 |
18 | @property (nonatomic) NSDictionary* allFields;
19 | @property (nonatomic) NSString* displayField;
20 | @property (nonatomic) NSArray* fields;
21 | @property (nonatomic) NSString* name;
22 | @property (nonatomic) NSString* userDescription;
23 |
24 | @end
25 |
26 | #pragma mark -
27 |
28 | @implementation CDAContentType
29 |
30 | +(NSString *)CDAType {
31 | return @"ContentType";
32 | }
33 |
34 | +(Class)fieldClass {
35 | return CDAField.class;
36 | }
37 |
38 | #pragma mark -
39 |
40 | -(NSString *)description {
41 | return [NSString stringWithFormat:@"CDAContentType %@ with %ld fields",
42 | self.name, (long)self.allFields.count];
43 | }
44 |
45 | -(CDAField*)fieldForIdentifier:(NSString *)identifier {
46 | return self.allFields[identifier];
47 | }
48 |
49 | -(instancetype)initWithDictionary:(NSDictionary *)dictionary
50 | client:(CDAClient*)client
51 | localizationAvailable:(BOOL)localizationAvailable {
52 | self = [super initWithDictionary:dictionary client:client localizationAvailable:localizationAvailable];
53 | if (self) {
54 | if (dictionary[@"name"]) {
55 | NSString* name = dictionary[@"name"];
56 | self.name = name;
57 | } else {
58 | [NSException raise:NSInvalidArgumentException format:@"Content-Types need a name"];
59 | }
60 |
61 | self.displayField = dictionary[@"displayField"];
62 | self.userDescription = dictionary[@"description"];
63 |
64 | NSMutableDictionary* allFields = [@{} mutableCopy];
65 | NSMutableArray* fields = [@[] mutableCopy];
66 |
67 | for (NSDictionary* field in dictionary[@"fields"]) {
68 | CDAField* fieldObject = [[[self.class fieldClass] alloc] initWithDictionary:field
69 | client:self.client
70 | localizationAvailable:localizationAvailable];
71 |
72 | allFields[fieldObject.identifier] = fieldObject;
73 | [fields addObject:fieldObject];
74 | }
75 |
76 | self.allFields = allFields;
77 | self.fields = fields;
78 |
79 | [self.client.contentTypeRegistry addContentType:self];
80 | }
81 | return self;
82 | }
83 |
84 | -(void)resolveWithSuccess:(void (^)(CDAResponse *, CDAResource *))success
85 | failure:(void (^)(CDAResponse *, NSError *))failure {
86 | if (self.fetched) {
87 | [super resolveWithSuccess:success failure:failure];
88 | return;
89 | }
90 |
91 | [self.client fetchContentTypeWithIdentifier:self.identifier
92 | success:^(CDAResponse *response, CDAContentType *contentType) {
93 | if (success) {
94 | success(response, contentType);
95 | }
96 | } failure:failure];
97 | }
98 |
99 | // We only encode properties that have write permissions
100 | #pragma mark - NSCoding
101 |
102 | -(instancetype)initWithCoder:(NSCoder *)aDecoder {
103 | self = [super initWithCoder:aDecoder];
104 | if (self) {
105 | self.allFields = [aDecoder decodeObjectForKey:@"allFields"];
106 | self.displayField = [aDecoder decodeObjectForKey:@"displayField"];
107 | self.fields = [aDecoder decodeObjectForKey:@"fields"];
108 | self.name = [aDecoder decodeObjectForKey:@"name"];
109 | self.userDescription = [aDecoder decodeObjectForKey:@"userDescription"];
110 | }
111 | return self;
112 | }
113 |
114 | -(void)encodeWithCoder:(NSCoder *)aCoder {
115 | [super encodeWithCoder:aCoder];
116 |
117 | [aCoder encodeObject:self.allFields forKey:@"allFields"];
118 | [aCoder encodeObject:self.displayField forKey:@"displayField"];
119 | [aCoder encodeObject:self.fields forKey:@"fields"];
120 | [aCoder encodeObject:self.name forKey:@"name"];
121 | [aCoder encodeObject:self.userDescription forKey:@"userDescription"];
122 |
123 | }
124 |
125 | @end
126 |
--------------------------------------------------------------------------------
/ContentfulSDK.xcodeproj/xcshareddata/xcschemes/ContentfulDeliveryAPI.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
45 |
46 |
48 |
54 |
55 |
56 |
57 |
58 |
64 |
65 |
66 |
67 |
68 |
69 |
79 |
80 |
86 |
87 |
88 |
89 |
90 |
91 |
97 |
98 |
104 |
105 |
106 |
107 |
109 |
110 |
113 |
114 |
115 |
--------------------------------------------------------------------------------
/ContentfulDeliveryAPI/CDAFieldValueTransformer.m:
--------------------------------------------------------------------------------
1 | //
2 | // CDAFieldValueTransformer.m
3 | // ContentfulSDK
4 | //
5 | // Created by Boris Bügling on 09/03/14.
6 | //
7 | //
8 |
9 | @import MapKit;
10 |
11 | #import
12 | #import "CDAClient+Private.h"
13 | #import "CDAFieldValueTransformer.h"
14 | #import "CDAResource+Private.h"
15 | #import "CDAUtilities.h"
16 |
17 | @interface CDAFieldValueTransformer ()
18 |
19 | @property (nonatomic, weak) CDAClient* client;
20 | @property (nonatomic) BOOL localizationAvailable;
21 | @property (nonatomic) CDAFieldType type;
22 |
23 | @end
24 |
25 | #pragma mark -
26 |
27 | @implementation CDAFieldValueTransformer
28 |
29 | +(BOOL)allowsReverseTransformation {
30 | return NO;
31 | }
32 |
33 | +(instancetype)transformerOfType:(CDAFieldType)type
34 | client:(CDAClient*)client
35 | localizationAvailable:(BOOL)localizationAvailable {
36 | return [[[self class] alloc] initWithType:type client:client localizationAvailable:localizationAvailable];
37 | }
38 |
39 | #pragma mark -
40 |
41 | -(instancetype)initWithType:(CDAFieldType)type
42 | client:(CDAClient*)client
43 | localizationAvailable:(BOOL)localizationAvailable {
44 | self = [super init];
45 | if (self) {
46 | NSParameterAssert(client);
47 | self.client = client;
48 |
49 | self.itemType = CDAFieldTypeNone;
50 | self.type = type;
51 | }
52 | return self;
53 | }
54 |
55 | -(id)locationFromDictionary:(NSDictionary*)dictionary {
56 | CLLocationCoordinate2D location;
57 | if ([dictionary isKindOfClass:[NSDictionary class]]) {
58 | location.latitude = [dictionary[@"lat"] doubleValue];
59 | location.longitude = [dictionary[@"lon"] doubleValue];
60 | }
61 | return [NSData dataWithBytes:&location length:sizeof(CLLocationCoordinate2D)];
62 | }
63 |
64 | -(id)transformArrayValue:(id)arrayValue {
65 | CDAFieldValueTransformer* transformer = [CDAFieldValueTransformer transformerOfType:self.itemType
66 | client:self.client
67 | localizationAvailable:self.localizationAvailable];
68 |
69 | NSMutableArray* array = [@[] mutableCopy];
70 | for (id value in arrayValue) {
71 | id transformedValue = [transformer transformedValue:value];
72 | if(transformedValue) {
73 | [array addObject:transformedValue];
74 | }
75 | }
76 |
77 | return [array copy];
78 | }
79 |
80 | -(id)transformedValue:(id)value {
81 | switch (self.type) {
82 | case CDAFieldTypeArray:
83 | if (value == [NSNull null] || ![value isKindOfClass:[NSArray class]]) {
84 | return @[];
85 | }
86 |
87 | return [self transformArrayValue:value];
88 |
89 | case CDAFieldTypeDate:
90 | if (value == [NSNull null] || ![value isKindOfClass:[NSString class]]) {
91 | return nil;
92 | }
93 |
94 | return [NSDate dateWithISO8601String:value];
95 |
96 | case CDAFieldTypeBoolean:
97 | case CDAFieldTypeInteger:
98 | case CDAFieldTypeNumber:
99 | if (value == [NSNull null] || ![value isKindOfClass:[NSNumber class]]) {
100 | return @0;
101 | }
102 |
103 | return value;
104 |
105 | case CDAFieldTypeObject:
106 | if (value == [NSNull null]) {
107 | return nil;
108 | }
109 |
110 | return value;
111 |
112 | case CDAFieldTypeAsset:
113 | case CDAFieldTypeEntry:
114 | case CDAFieldTypeLink:
115 | if (value == [NSNull null]) {
116 | return nil;
117 | }
118 |
119 | return [CDAResource resourceObjectForDictionary:value
120 | client:self.client
121 | localizationAvailable:self.localizationAvailable];
122 |
123 | case CDAFieldTypeLocation:
124 | if (value == [NSNull null]) {
125 | return nil;
126 | }
127 |
128 | return [self locationFromDictionary:value];
129 |
130 | case CDAFieldTypeSymbol:
131 | case CDAFieldTypeText:
132 | if (value == [NSNull null]) {
133 | return @"";
134 | }
135 |
136 | if ([value isKindOfClass:[NSString class]]) {
137 | return value;
138 | } else {
139 | if (![value respondsToSelector:@selector(stringValue)]) {
140 | return @"";
141 | }
142 | return [value stringValue];
143 | }
144 |
145 | case CDAFieldTypeNone:
146 | break;
147 | }
148 |
149 | NSAssert(false, @"Unhandled field type '%ld'", (long)self.type);
150 | return nil;
151 | }
152 |
153 | @end
154 |
--------------------------------------------------------------------------------
/Tests/Data/Fixtures/ContentType-001.json:
--------------------------------------------------------------------------------
1 | {
2 | "fields": [
3 | {
4 | "name": "Entry Type",
5 | "id": "entryType",
6 | "type": "Text"
7 | },
8 | {
9 | "name": "Main Image",
10 | "id": "mainImage",
11 | "type": "Link",
12 | "linkType": "Asset"
13 | },
14 | {
15 | "name": "Main Headline",
16 | "id": "mainHeadline",
17 | "type": "Text"
18 | },
19 | {
20 | "name": "Main Body",
21 | "id": "mainBody",
22 | "type": "Text"
23 | },
24 | {
25 | "name": "Should Show Teaser?",
26 | "id": "showTeaser",
27 | "type": "Boolean"
28 | },
29 | {
30 | "name": "Teaser Headline",
31 | "id": "teaserHeadline",
32 | "type": "Text"
33 | },
34 | {
35 | "name": "Teaser Text",
36 | "id": "teaserText",
37 | "type": "Text"
38 | },
39 | {
40 | "name": "Teaser Text Long",
41 | "id": "teaserTextLong",
42 | "type": "Text"
43 | },
44 | {
45 | "name": "Gallery Images",
46 | "id": "galleryImages",
47 | "type": "Array",
48 | "items": {
49 | "type": "Link",
50 | "linkType": "Asset"
51 | },
52 | "disabled": true
53 | },
54 | {
55 | "name": "Quiz Answer",
56 | "id": "quizAnswer",
57 | "type": "Text",
58 | "disabled": true
59 | },
60 | {
61 | "name": "Channel",
62 | "id": "channel",
63 | "type": "Link",
64 | "linkType": "Entry"
65 | },
66 | {
67 | "name": "Push Message",
68 | "id": "pushMessage",
69 | "type": "Text",
70 | "disabled": true
71 | },
72 | {
73 | "name": "Push Message on Entry",
74 | "id": "pushMessageOnEntry",
75 | "type": "Boolean",
76 | "disabled": true
77 | },
78 | {
79 | "name": "Push Message on Exit",
80 | "id": "pushMessageOnExit",
81 | "type": "Boolean",
82 | "disabled": true
83 | },
84 | {
85 | "name": "UUID",
86 | "id": "uuid",
87 | "type": "Integer",
88 | "disabled": true
89 | },
90 | {
91 | "name": "UUID Assgn",
92 | "id": "uuidAssgn",
93 | "type": "Link",
94 | "linkType": "Entry"
95 | },
96 | {
97 | "name": "For Any Zone?",
98 | "id": "locationIsAll",
99 | "type": "Boolean"
100 | },
101 | {
102 | "name": "Zones",
103 | "id": "multipleLocations",
104 | "type": "Array",
105 | "items": {
106 | "type": "Link",
107 | "linkType": "Entry",
108 | "validations": [
109 | {
110 | "linkContentType": "Xvzf8HzuUweuwK0WuKuUq"
111 | }
112 | ]
113 | }
114 | },
115 | {
116 | "name": "Beacon Major Value",
117 | "id": "beaconMajorValue",
118 | "type": "Integer",
119 | "disabled": true
120 | },
121 | {
122 | "name": "Beacon Minor is All",
123 | "id": "beaconMinorIsAll",
124 | "type": "Boolean",
125 | "disabled": true
126 | },
127 | {
128 | "name": "Beacon Minor Value",
129 | "id": "beaconMinorValue",
130 | "type": "Integer",
131 | "disabled": true
132 | },
133 | {
134 | "name": "Beacon",
135 | "id": "beacon",
136 | "type": "Link",
137 | "linkType": "Entry",
138 | "disabled": false
139 | },
140 | {
141 | "name": "BeaconProximity",
142 | "id": "beaconProximity",
143 | "type": "Text"
144 | },
145 | {
146 | "name": "BeaconType",
147 | "id": "beaconType",
148 | "type": "Link",
149 | "linkType": "Entry",
150 | "disabled": true
151 | },
152 | {
153 | "name": "BeaconEngagementType",
154 | "id": "beaconEngagementType",
155 | "type": "Text",
156 | "disabled": true
157 | },
158 | {
159 | "name": "Location",
160 | "id": "location",
161 | "type": "Link",
162 | "linkType": "Entry",
163 | "disabled": true
164 | },
165 | {
166 | "name": "Beacon Minor",
167 | "id": "beaconMinor",
168 | "type": "Text",
169 | "disabled": true
170 | },
171 | {
172 | "name": "Location All",
173 | "id": "locationAll",
174 | "type": "Text",
175 | "disabled": true
176 | },
177 | {
178 | "name": "TempMajorValue",
179 | "id": "tempMajorValue",
180 | "type": "Integer",
181 | "disabled": true
182 | },
183 | {
184 | "name": "TempMinorValue",
185 | "id": "tempMinorValue",
186 | "type": "Integer",
187 | "disabled": true
188 | },
189 | {
190 | "name": "Video URL",
191 | "id": "videoUrl",
192 | "type": "Text"
193 | }
194 | ],
195 | "name": "Main Post",
196 | "description": "Main posts - standard format with links to additional post types",
197 | "displayField": "mainHeadline",
198 | "sys": {
199 | "space": {
200 | "sys": {
201 | "type": "Link",
202 | "linkType": "Space",
203 | "id": "k7cpvwpbb4c0"
204 | }
205 | },
206 | "type": "ContentType",
207 | "id": "2KZUNxrxfyYC8qO42o0oMQ",
208 | "revision": 4,
209 | "createdAt": "2014-09-28T20:03:07.383Z",
210 | "updatedAt": "2014-10-03T12:40:29.135Z",
211 | "locale": "en-US"
212 | }
213 | }
214 |
--------------------------------------------------------------------------------
/Tests/Data/ComplexSyncTests/AssetTestInitial.json:
--------------------------------------------------------------------------------
1 | {
2 | "sys": {
3 | "type": "Array"
4 | },
5 | "items": [
6 | {
7 | "sys": {
8 | "space": {
9 | "sys": {
10 | "type": "Link",
11 | "linkType": "Space",
12 | "id": "emh6o2ireilu"
13 | }
14 | },
15 | "type": "Entry",
16 | "contentType": {
17 | "sys": {
18 | "type": "Link",
19 | "linkType": "ContentType",
20 | "id": "6bAvxqodl6s4MoKuWYkmqe"
21 | }
22 | },
23 | "id": "1Wl5HnguK8CiaykiQAiGu6",
24 | "revision": 1,
25 | "createdAt": "2014-04-09T11:48:47.866Z",
26 | "updatedAt": "2014-04-09T11:48:47.866Z"
27 | },
28 | "fields": {
29 | "title": {
30 | "en-US": "WithCategory"
31 | },
32 | "body": {
33 | "en-US": "some text"
34 | },
35 | "category": {
36 | "en-US": {
37 | "sys": {
38 | "type": "Link",
39 | "linkType": "Entry",
40 | "id": "6nRlw4CofeeICEYgIqaIIg"
41 | }
42 | }
43 | }
44 | }
45 | },
46 | {
47 | "sys": {
48 | "space": {
49 | "sys": {
50 | "type": "Link",
51 | "linkType": "Space",
52 | "id": "emh6o2ireilu"
53 | }
54 | },
55 | "type": "Entry",
56 | "contentType": {
57 | "sys": {
58 | "type": "Link",
59 | "linkType": "ContentType",
60 | "id": "51LZmvenywOe8aig28sCgY"
61 | }
62 | },
63 | "id": "6nRlw4CofeeICEYgIqaIIg",
64 | "revision": 1,
65 | "createdAt": "2014-04-09T11:48:42.407Z",
66 | "updatedAt": "2014-04-09T11:48:42.407Z"
67 | },
68 | "fields": {
69 | "name": {
70 | "en-US": "foobar"
71 | }
72 | }
73 | },
74 | {
75 | "sys": {
76 | "space": {
77 | "sys": {
78 | "type": "Link",
79 | "linkType": "Space",
80 | "id": "emh6o2ireilu"
81 | }
82 | },
83 | "type": "Entry",
84 | "contentType": {
85 | "sys": {
86 | "type": "Link",
87 | "linkType": "ContentType",
88 | "id": "51LZmvenywOe8aig28sCgY"
89 | }
90 | },
91 | "id": "1YCXOBW1xu2uSkekCmwyqo",
92 | "revision": 1,
93 | "createdAt": "2014-04-09T11:44:21.359Z",
94 | "updatedAt": "2014-04-09T11:44:21.359Z"
95 | },
96 | "fields": {
97 | "name": {
98 | "en-US": "Some Category"
99 | }
100 | }
101 | },
102 | {
103 | "fields": {
104 | "title": {
105 | "en-US": "doge (changed)"
106 | },
107 | "file": {
108 | "en-US": {
109 | "fileName": "vaa4by0.png",
110 | "contentType": "image/png",
111 | "details": {
112 | "image": {
113 | "width": 265,
114 | "height": 265
115 | },
116 | "size": 103652
117 | },
118 | "url": "//images.contentful.com/emh6o2ireilu/6koKmTXVzUquae6ewQQ8Eu/5f79cef98e3feb466c30f0b38bec0359/vaa4by0.png"
119 | }
120 | }
121 | },
122 | "sys": {
123 | "space": {
124 | "sys": {
125 | "type": "Link",
126 | "linkType": "Space",
127 | "id": "emh6o2ireilu"
128 | }
129 | },
130 | "type": "Asset",
131 | "id": "6koKmTXVzUquae6ewQQ8Eu",
132 | "revision": 2,
133 | "createdAt": "2014-03-25T11:08:25.412Z",
134 | "updatedAt": "2014-03-26T10:37:20.069Z"
135 | }
136 | },
137 | {
138 | "sys": {
139 | "space": {
140 | "sys": {
141 | "type": "Link",
142 | "linkType": "Space",
143 | "id": "emh6o2ireilu"
144 | }
145 | },
146 | "type": "Entry",
147 | "contentType": {
148 | "sys": {
149 | "type": "Link",
150 | "linkType": "ContentType",
151 | "id": "6bAvxqodl6s4MoKuWYkmqe"
152 | }
153 | },
154 | "id": "4upDPGUMMEkG8w8UUs2OiO",
155 | "revision": 2,
156 | "createdAt": "2014-03-25T11:00:43.065Z",
157 | "updatedAt": "2014-03-26T10:37:09.128Z"
158 | },
159 | "fields": {
160 | "title": {
161 | "en-US": "Test (changed)"
162 | },
163 | "body": {
164 | "en-US": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
165 | }
166 | }
167 | }
168 | ],
169 | "nextSyncUrl": "http://cdn.contentful.com/spaces/emh6o2ireilu/sync?sync_token=w5ZGw6JFwqZmVcKsE8Kow4grw45QdyZ7T8Obw5Inwoh6Tk7Cq8KUDcK7w5ssw6vCgjLDjk9Hwr3DusOzw7XCo8OIwo3CicK5SBkqCcK7woDDhSjCkMOGw7rCqMOtE1V1L3LDq8KIck_DssK4K8OBe0vDn0vDrXjDkMOf"
170 | }
171 |
--------------------------------------------------------------------------------