├── CHANGELOG.md ├── contributors.txt ├── MyTasks ├── up.png ├── icon.png ├── Default.png ├── Assets.xcassets │ ├── Contents.json │ ├── Image.imageset │ │ ├── icon.png │ │ ├── Default.png │ │ ├── Default@2X.png │ │ └── Contents.json │ └── AppIcon.appiconset │ │ └── Contents.json ├── Default@2X.png ├── icon_small.png ├── TaskItem.m ├── BasicAuthHandle.h ├── LoginProgressViewController.h ├── OAuthHandle.h ├── DetailViewController.h ├── LoginViewController.h ├── AFHTTPSessionManagerFactory.h ├── main.m ├── TaskListViewController.h ├── AppDelegate.h ├── AuthSession.h ├── TaskItem.h ├── AuthHandle.h ├── APIRequestMonitor.h ├── Authenticator.h ├── AuthSession.m ├── AuthHandle.m ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist ├── Properties.h ├── RestAPIRequestHandler.h ├── AFHTTPSessionManagerFactory.m ├── Properties.m ├── Authenticator.m ├── LoginProgressViewController.m ├── BasicAuthHandle.m ├── LoginViewController.m ├── APIRequestMonitor.m ├── AppDelegate.m ├── RestAPIRequestHandler.m ├── OAuthHandle.m ├── DetailViewController.m └── TaskListViewController.m ├── images ├── login.png ├── node_flow.png ├── task_detail.png ├── task_list.png ├── arch_diagram.jpg ├── build_and_run.png └── pod_install_result.png ├── MyTasks.xcodeproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── project.pbxproj ├── Podfile ├── LICENSE.txt ├── README.md └── mywork_update_set └── sys_remote_update_set_2f48a7d74f4652002fa02f1e0210c785.xml /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## Change Log 2 | 3 | ### v1.00.0 (2016/04/20) 4 | -------------------------------------------------------------------------------- /contributors.txt: -------------------------------------------------------------------------------- 1 | venkata.koya 2 | silas.smith 3 | bryan.barnard 4 | -------------------------------------------------------------------------------- /MyTasks/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServiceNow/example-restclient-myworkapp-ios/HEAD/MyTasks/up.png -------------------------------------------------------------------------------- /MyTasks/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServiceNow/example-restclient-myworkapp-ios/HEAD/MyTasks/icon.png -------------------------------------------------------------------------------- /images/login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServiceNow/example-restclient-myworkapp-ios/HEAD/images/login.png -------------------------------------------------------------------------------- /MyTasks/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServiceNow/example-restclient-myworkapp-ios/HEAD/MyTasks/Default.png -------------------------------------------------------------------------------- /MyTasks/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /MyTasks/Default@2X.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServiceNow/example-restclient-myworkapp-ios/HEAD/MyTasks/Default@2X.png -------------------------------------------------------------------------------- /MyTasks/icon_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServiceNow/example-restclient-myworkapp-ios/HEAD/MyTasks/icon_small.png -------------------------------------------------------------------------------- /images/node_flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServiceNow/example-restclient-myworkapp-ios/HEAD/images/node_flow.png -------------------------------------------------------------------------------- /images/task_detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServiceNow/example-restclient-myworkapp-ios/HEAD/images/task_detail.png -------------------------------------------------------------------------------- /images/task_list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServiceNow/example-restclient-myworkapp-ios/HEAD/images/task_list.png -------------------------------------------------------------------------------- /images/arch_diagram.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServiceNow/example-restclient-myworkapp-ios/HEAD/images/arch_diagram.jpg -------------------------------------------------------------------------------- /images/build_and_run.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServiceNow/example-restclient-myworkapp-ios/HEAD/images/build_and_run.png -------------------------------------------------------------------------------- /images/pod_install_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServiceNow/example-restclient-myworkapp-ios/HEAD/images/pod_install_result.png -------------------------------------------------------------------------------- /MyTasks/Assets.xcassets/Image.imageset/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServiceNow/example-restclient-myworkapp-ios/HEAD/MyTasks/Assets.xcassets/Image.imageset/icon.png -------------------------------------------------------------------------------- /MyTasks/Assets.xcassets/Image.imageset/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServiceNow/example-restclient-myworkapp-ios/HEAD/MyTasks/Assets.xcassets/Image.imageset/Default.png -------------------------------------------------------------------------------- /MyTasks/Assets.xcassets/Image.imageset/Default@2X.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ServiceNow/example-restclient-myworkapp-ios/HEAD/MyTasks/Assets.xcassets/Image.imageset/Default@2X.png -------------------------------------------------------------------------------- /MyTasks.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | platform :ios, '8.0' 3 | # Uncomment this line if you're using Swift 4 | # use_frameworks! 5 | # 6 | pod 'SSKeychain' 7 | pod 'AFNetworking', '~> 3.0.4' 8 | 9 | target 'MyTasks' do 10 | 11 | end 12 | 13 | -------------------------------------------------------------------------------- /MyTasks/Assets.xcassets/Image.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Default.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "Default@2X.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "icon.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /MyTasks/TaskItem.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 ServiceNow, Inc. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions 10 | of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 12 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 13 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 14 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 15 | IN THE SOFTWARE. 16 | */ 17 | 18 | #import "TaskItem.h" 19 | 20 | @implementation TaskItem 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /MyTasks/BasicAuthHandle.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 ServiceNow, Inc. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions 10 | of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 12 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 13 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 14 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 15 | IN THE SOFTWARE. 16 | */ 17 | 18 | #import "AuthHandle.h" 19 | 20 | @interface BasicAuthHandle : AuthHandle 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /MyTasks/LoginProgressViewController.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 ServiceNow, Inc. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions 10 | of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 12 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 13 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 14 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 15 | IN THE SOFTWARE. 16 | */ 17 | 18 | #import 19 | 20 | @interface LoginProgressViewController : UIViewController 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /MyTasks/OAuthHandle.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 ServiceNow, Inc. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions 10 | of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 12 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 13 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 14 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 15 | IN THE SOFTWARE. 16 | */ 17 | 18 | #import "AuthHandle.h" 19 | 20 | @interface OAuthHandle : AuthHandle{ 21 | NSString *_clientId; 22 | NSString *_clientSecret; 23 | } 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /MyTasks/DetailViewController.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 ServiceNow, Inc. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions 10 | of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 12 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 13 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 14 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 15 | IN THE SOFTWARE. 16 | */ 17 | 18 | #import 19 | #import "TaskItem.h" 20 | 21 | @interface DetailViewController : UITableViewController 22 | 23 | @property TaskItem *item; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /MyTasks/LoginViewController.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 ServiceNow, Inc. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions 10 | of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 12 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 13 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 14 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 15 | IN THE SOFTWARE. 16 | */ 17 | 18 | #import 19 | #import "Authenticator.h" 20 | 21 | @interface LoginViewController : UIViewController{ 22 | Authenticator *_authenticator; 23 | } 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /MyTasks/AFHTTPSessionManagerFactory.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 ServiceNow, Inc. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions 10 | of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 12 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 13 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 14 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 15 | IN THE SOFTWARE. 16 | */ 17 | 18 | #import 19 | #import "AFNetworking.h" 20 | 21 | @interface AFHTTPSessionManagerFactory : NSObject 22 | 23 | +(AFHTTPSessionManager *)sharedManager; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /MyTasks/main.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 ServiceNow, Inc. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions 10 | of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 12 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 13 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 14 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 15 | IN THE SOFTWARE. 16 | */ 17 | 18 | #import 19 | #import "AppDelegate.h" 20 | 21 | int main(int argc, char * argv[]) { 22 | @autoreleasepool { 23 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /MyTasks/TaskListViewController.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 ServiceNow, Inc. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions 10 | of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 12 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 13 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 14 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 15 | IN THE SOFTWARE. 16 | */ 17 | 18 | #import 19 | 20 | @interface TaskListViewController : UITableViewController 21 | 22 | @property (strong, nonatomic) NSDictionary *result; 23 | @property (strong, nonatomic) NSArray *sections; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /MyTasks/AppDelegate.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 ServiceNow, Inc. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions 10 | of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 12 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 13 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 14 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 15 | IN THE SOFTWARE. 16 | */ 17 | 18 | #import 19 | 20 | @interface AppDelegate : UIResponder { 21 | bool registered; 22 | NSString *deviceToken; 23 | } 24 | 25 | - (void)sendDeviceToken; 26 | 27 | @property (strong, nonatomic) UIWindow *window; 28 | 29 | 30 | @end 31 | 32 | -------------------------------------------------------------------------------- /MyTasks/AuthSession.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 ServiceNow, Inc. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions 10 | of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 12 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 13 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 14 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 15 | IN THE SOFTWARE. 16 | */ 17 | 18 | #import 19 | 20 | @interface AuthSession : NSObject{ 21 | BOOL isAuthenticated; 22 | } 23 | 24 | @property NSString *name; 25 | 26 | +(AuthSession *)sharedSession; 27 | 28 | - (void) setAuthenticated:(BOOL)isAuthed; 29 | 30 | - (BOOL) isAuthenticated; 31 | @end 32 | -------------------------------------------------------------------------------- /MyTasks/TaskItem.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 ServiceNow, Inc. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions 10 | of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 12 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 13 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 14 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 15 | IN THE SOFTWARE. 16 | */ 17 | 18 | #import 19 | 20 | @interface TaskItem : NSObject 21 | 22 | @property NSString *tableName; 23 | @property NSString *number; 24 | @property NSString *sysId; 25 | @property NSString *shortDescription; 26 | @property NSString *opened; 27 | @property NSString *comment; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /MyTasks/AuthHandle.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 ServiceNow, Inc. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions 10 | of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 12 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 13 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 14 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 15 | IN THE SOFTWARE. 16 | */ 17 | 18 | #import 19 | 20 | @interface AuthHandle : NSObject{ 21 | 22 | } 23 | 24 | - (void)authenticate:(NSString *) userName password:(NSString *)password; 25 | 26 | - (void)authenticateUsingKeyChain; 27 | 28 | -(void) populateUserSession:(NSString *)name; 29 | 30 | - (void) logout; 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /MyTasks/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "83.5x83.5", 66 | "scale" : "2x" 67 | } 68 | ], 69 | "info" : { 70 | "version" : 1, 71 | "author" : "xcode" 72 | } 73 | } -------------------------------------------------------------------------------- /MyTasks/APIRequestMonitor.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 ServiceNow, Inc. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions 10 | of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 12 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 13 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 14 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 15 | IN THE SOFTWARE. 16 | */ 17 | 18 | 19 | #import 20 | #import 21 | #import "AFHTTPSessionManagerFactory.h" 22 | 23 | @interface APIRequestMonitor : NSObject 24 | 25 | @property (nonatomic, strong) UIAlertView *loadMessageView; 26 | @property (nonatomic, strong) UIView *mask; 27 | 28 | + (instancetype) _sharedRequestMonitor; 29 | 30 | - (void)startMontoring; 31 | 32 | - (void)stopMontoring; 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /MyTasks/Authenticator.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 ServiceNow, Inc. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions 10 | of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 12 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 13 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 14 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 15 | IN THE SOFTWARE. 16 | */ 17 | 18 | #import 19 | #import "AuthHandle.h" 20 | #import "AuthSession.h" 21 | 22 | @interface Authenticator : NSObject{ 23 | AuthHandle *_authHandle; 24 | AuthSession * _session; 25 | } 26 | 27 | +(Authenticator *)sharedAuthenticator; 28 | 29 | -(id)initWithOAuth; 30 | 31 | -(void)authenticate:(NSString *)userName password:(NSString *)password; 32 | 33 | -(void) authenticateFromKeyChain; 34 | 35 | -(void) logout; 36 | 37 | - (BOOL) isAuthenticated; 38 | @end 39 | -------------------------------------------------------------------------------- /MyTasks/AuthSession.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 ServiceNow, Inc. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions 10 | of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 12 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 13 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 14 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 15 | IN THE SOFTWARE. 16 | */ 17 | 18 | #import "AuthSession.h" 19 | 20 | @implementation AuthSession 21 | 22 | static AuthSession *session = nil; 23 | 24 | +(AuthSession *)sharedSession;{ 25 | if (session == nil) { 26 | session = [[super alloc] init]; 27 | } 28 | return session; 29 | } 30 | 31 | - (void) setAuthenticated:(BOOL)isAuthed;{ 32 | isAuthenticated = isAuthed; 33 | } 34 | 35 | - (BOOL) isAuthenticated;{ 36 | return isAuthenticated; 37 | } 38 | 39 | - (id)copyWithZone:(NSZone *)zone { 40 | return self; 41 | } 42 | 43 | - (id)copy; { 44 | return self; 45 | } 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /MyTasks/AuthHandle.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 ServiceNow, Inc. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions 10 | of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 12 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 13 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 14 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 15 | IN THE SOFTWARE. 16 | */ 17 | 18 | #import "AuthHandle.h" 19 | #import "AuthSession.h" 20 | 21 | @implementation AuthHandle 22 | 23 | -(id)init;{ 24 | self = [super init]; 25 | return self; 26 | } 27 | 28 | - (void)authenticate:(NSString *) userName password:(NSString *)password;{ 29 | 30 | } 31 | 32 | - (void)authenticateUsingKeyChain;{ 33 | 34 | } 35 | 36 | -(void) populateUserSession:(NSString *)name{ 37 | 38 | AuthSession *userSession = [AuthSession sharedSession]; 39 | [userSession setAuthenticated:YES]; 40 | userSession.name = name; 41 | } 42 | 43 | -(void) logout;{ 44 | 45 | } 46 | @end 47 | -------------------------------------------------------------------------------- /MyTasks/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /MyTasks/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSAppTransportSecurity 6 | 7 | NSAllowsArbitraryLoads 8 | 9 | 10 | CFBundleDevelopmentRegion 11 | en 12 | CFBundleExecutable 13 | $(EXECUTABLE_NAME) 14 | CFBundleIdentifier 15 | $(PRODUCT_BUNDLE_IDENTIFIER) 16 | CFBundleInfoDictionaryVersion 17 | 6.0 18 | CFBundleName 19 | $(PRODUCT_NAME) 20 | CFBundlePackageType 21 | APPL 22 | CFBundleShortVersionString 23 | 1.0 24 | CFBundleSignature 25 | ???? 26 | CFBundleVersion 27 | 1 28 | LSRequiresIPhoneOS 29 | 30 | UILaunchStoryboardName 31 | Main 32 | UIMainStoryboardFile 33 | Main 34 | UIRequiredDeviceCapabilities 35 | 36 | armv7 37 | 38 | UISupportedInterfaceOrientations 39 | 40 | UIInterfaceOrientationPortrait 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | UISupportedInterfaceOrientations~ipad 45 | 46 | UIInterfaceOrientationPortrait 47 | UIInterfaceOrientationPortraitUpsideDown 48 | UIInterfaceOrientationLandscapeLeft 49 | UIInterfaceOrientationLandscapeRight 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /MyTasks/Properties.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 ServiceNow, Inc. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions 10 | of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 12 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 13 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 14 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 15 | IN THE SOFTWARE. 16 | */ 17 | 18 | #import 19 | #define USER_NAME @"username" 20 | #define PASSWORD @"password" 21 | #define AUTH_TYPE @"authType" 22 | #define BASIC @"Basic" 23 | #define HOST_NAME @"host_name" 24 | #define INSTANCE_NAME @"instance_name" 25 | #define LOGIN_EVENT @"login_event" 26 | #define KEYCHAIN_LOGIN_EVENT @"ks_login_event" 27 | #define KEYCHAIN_APP_ID @"com.now.api.MyTasks" 28 | #define DOMAIN_NAME @".service-now.com" 29 | #define PROTOCOL @"https://" 30 | #define OAUTH_CLIENT_ID_VALUE @"4351eb7c311d1240026d7202c346b092" 31 | #define OAUTH_CLIENT_SECRET_VALUE @"C*AQK`J*:a" 32 | 33 | @interface Properties : NSObject{ 34 | 35 | } 36 | 37 | +(void) setInstanceName:(NSString *)instanceName; 38 | +(NSString *) getHostName; 39 | +(NSString *) getInstanceName; 40 | +(NSString *) getBaseURL; 41 | +(NSString *) getAPPID; 42 | +(NSString *)getClientId; 43 | +(NSString *)getClientSecret; 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /MyTasks/RestAPIRequestHandler.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 ServiceNow, Inc. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions 10 | of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 12 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 13 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 14 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 15 | IN THE SOFTWARE. 16 | */ 17 | 18 | #import 19 | #import "AFNetworking.h" 20 | 21 | @interface RestAPIRequestHandler : NSObject 22 | 23 | @property(strong) NSArray *results; 24 | @property(strong) AFHTTPSessionManager *manager; 25 | 26 | -(void) getTaskComments:(NSString*) taskId success: (void (^) (NSArray* response))success failure:(void (^)(NSError* error))failure; 27 | 28 | -(void) getAssignedTasks:(void (^)(NSDictionary* result))success failure:(void (^)(NSURLSessionDataTask * _Nullable task, NSError* error))failure; 29 | 30 | -(void) getTaskDetails:(NSString*) taskId success: (void (^) (NSDictionary* result))success failure:(void (^)(NSError* error))failure; 31 | 32 | -(void) postComment:(NSString*) comment onTask: (NSString*) taskId success: (void (^) (NSDictionary* result))success failure:(void (^)(NSError* error))failure; 33 | 34 | -(void) postInstallation:(NSString*) token success: (void (^) (NSDictionary* result))success failure:(void (^)(NSError* error))failure; 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /MyTasks/AFHTTPSessionManagerFactory.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 ServiceNow, Inc. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions 10 | of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 12 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 13 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 14 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 15 | IN THE SOFTWARE. 16 | */ 17 | 18 | #import "AFHTTPSessionManagerFactory.h" 19 | #import "AFNetworking.h" 20 | #import "Properties.h" 21 | 22 | @implementation AFHTTPSessionManagerFactory 23 | 24 | + (AFHTTPSessionManager *)sharedManager;{ 25 | NSURL *baseUrl = [[NSURL alloc]initWithString:[Properties getBaseURL]]; 26 | NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; 27 | AFHTTPSessionManager *manager = [[AFHTTPSessionManager manager] initWithBaseURL:baseUrl sessionConfiguration: 28 | configuration]; 29 | manager.requestSerializer = [AFJSONRequestSerializer serializer]; 30 | [manager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Accept"]; 31 | [manager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; 32 | manager.responseSerializer = [AFJSONResponseSerializer serializer]; 33 | 34 | //TODO: Remove this QUIRK used in dev 35 | manager.securityPolicy.allowInvalidCertificates = YES; 36 | manager.securityPolicy.validatesDomainName = NO; 37 | return manager; 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /MyTasks/Properties.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 ServiceNow, Inc. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions 10 | of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 12 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 13 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 14 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 15 | IN THE SOFTWARE. 16 | */ 17 | 18 | #import "Properties.h" 19 | #import "SSKeychain.h" 20 | 21 | @implementation Properties 22 | 23 | +(void) setInstanceName:(NSString *)instanceName { 24 | [SSKeychain setPassword:instanceName 25 | forService: [Properties getAPPID] 26 | account:INSTANCE_NAME]; 27 | } 28 | 29 | + (NSString *) getInstanceName;{ 30 | return [SSKeychain passwordForService:[Properties getAPPID] account:INSTANCE_NAME]; 31 | } 32 | 33 | + (NSString *) getHostName;{ 34 | NSString * instanceName = [self getInstanceName]; 35 | 36 | if([instanceName length] ==0) { 37 | return @""; 38 | } 39 | 40 | NSString *hostName = [instanceName hasSuffix:DOMAIN_NAME] ? instanceName : [instanceName stringByAppendingString:DOMAIN_NAME]; 41 | 42 | NSString *fullHostName = [hostName hasPrefix:PROTOCOL] ?hostName:[PROTOCOL stringByAppendingString:hostName]; 43 | 44 | return fullHostName; 45 | } 46 | 47 | + (NSString *) getBaseURL;{ 48 | return [self getHostName]; 49 | } 50 | 51 | + (NSString *) getAPPID;{ 52 | return KEYCHAIN_APP_ID; 53 | } 54 | 55 | +(NSString *)getClientId;{ 56 | return OAUTH_CLIENT_ID_VALUE; 57 | } 58 | 59 | +(NSString *)getClientSecret;{ 60 | return OAUTH_CLIENT_SECRET_VALUE; 61 | } 62 | 63 | @end 64 | -------------------------------------------------------------------------------- /MyTasks/Authenticator.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 ServiceNow, Inc. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions 10 | of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 12 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 13 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 14 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 15 | IN THE SOFTWARE. 16 | */ 17 | 18 | #import "Authenticator.h" 19 | #import "BasicAuthHandle.h" 20 | #import "OAuthHandle.h" 21 | #import "SSKeychain.h" 22 | #import "AFNetworking.h" 23 | 24 | @interface Authenticator() 25 | - (void)populateAuthSession:(BOOL)authenticated; 26 | @end 27 | 28 | @implementation Authenticator 29 | 30 | static Authenticator *authenticator = nil; 31 | 32 | +(Authenticator *)sharedAuthenticator;{ 33 | if (authenticator == nil) { 34 | authenticator = [[super alloc] init]; 35 | // authenticator = [[super alloc] initWithOAuth]; 36 | } 37 | return authenticator; 38 | } 39 | 40 | -(id)init;{ 41 | self = [super init]; 42 | _authHandle=[[BasicAuthHandle alloc]init]; 43 | _session = [AuthSession sharedSession]; 44 | 45 | return self; 46 | } 47 | 48 | -(id)initWithOAuth;{ 49 | self = [super init]; 50 | _authHandle=[[OAuthHandle alloc]init]; 51 | _session = [AuthSession sharedSession]; 52 | return self; 53 | } 54 | 55 | - (BOOL) isAuthenticated;{ 56 | return [_session isAuthenticated]; 57 | } 58 | 59 | -(void)authenticate:(NSString *)userName password:(NSString *)password;{ 60 | [_authHandle authenticate:userName password:password]; 61 | } 62 | 63 | -(void) authenticateFromKeyChain;{ 64 | 65 | [_authHandle authenticateUsingKeyChain]; 66 | } 67 | 68 | -(void) logout;{ 69 | [_authHandle logout]; 70 | [self populateAuthSession:NO]; 71 | } 72 | 73 | - (void)populateAuthSession:(BOOL)authenticated; { 74 | [_session setAuthenticated:authenticated]; 75 | } 76 | 77 | @end 78 | -------------------------------------------------------------------------------- /MyTasks/LoginProgressViewController.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 ServiceNow, Inc. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions 10 | of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 12 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 13 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 14 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 15 | IN THE SOFTWARE. 16 | */ 17 | 18 | #import "LoginProgressViewController.h" 19 | #import "Authenticator.h" 20 | #import "Properties.h" 21 | #import "AppDelegate.h" 22 | 23 | @interface LoginProgressViewController () 24 | 25 | @end 26 | 27 | @implementation LoginProgressViewController 28 | 29 | - (void)viewDidLoad { 30 | [super viewDidLoad]; 31 | [self authenticationCheck]; 32 | } 33 | 34 | -(void)authenticationCheck;{ 35 | // If not authenticated. Most of the time when launching, it is not, show indicator view(or some non login required view) while we try to authenticate from Keychain data 36 | 37 | Authenticator *authenticator=[Authenticator sharedAuthenticator]; 38 | 39 | if(![authenticator isAuthenticated]) { 40 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loginEventListener:) name:KEYCHAIN_LOGIN_EVENT object:nil]; 41 | 42 | [authenticator authenticateFromKeyChain]; 43 | // Loading Login progress view: redirected here from App delegate waiting for authentication using keychain data. 44 | // Listen for Login Event 45 | 46 | } else { 47 | UIViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:@"TaskListViewNavController"]; 48 | [self presentViewController:vc animated:YES completion:nil]; 49 | } 50 | } 51 | 52 | -(void) loginEventListener:(NSNotification *) ntfcn { 53 | AuthSession *session = [AuthSession sharedSession]; 54 | 55 | if([session isAuthenticated]) { 56 | AppDelegate* appDelegate = (AppDelegate*)[[UIApplication sharedApplication]delegate]; 57 | [appDelegate sendDeviceToken]; 58 | 59 | UIViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:@"TaskListViewNavController"]; 60 | [self presentViewController:vc animated:YES completion:nil]; 61 | } else { 62 | UIViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:@"LoginViewNavController"]; 63 | [vc setModalPresentationStyle:UIModalPresentationFullScreen]; 64 | [self presentViewController:vc animated:YES completion:nil]; 65 | } 66 | } 67 | 68 | - (void)didReceiveMemoryWarning { 69 | [super didReceiveMemoryWarning]; 70 | } 71 | 72 | @end 73 | -------------------------------------------------------------------------------- /MyTasks/BasicAuthHandle.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 ServiceNow, Inc. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions 10 | of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 12 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 13 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 14 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 15 | IN THE SOFTWARE. 16 | */ 17 | 18 | #import "BasicAuthHandle.h" 19 | #import "SSKeychain.h" 20 | #import "Properties.h" 21 | #import "AFHTTPSessionManagerFactory.h" 22 | #import "AFNetworking.h" 23 | #import "AuthSession.h" 24 | #import "AFNetworking/AFURLResponseSerialization.h" 25 | 26 | @implementation BasicAuthHandle 27 | 28 | -(void) authenticate:(NSString *)userName password:(NSString *)password;{ 29 | 30 | [self login:userName password:password fromKeyChain:NO]; 31 | 32 | } 33 | 34 | - (void)authenticateUsingKeyChain; { 35 | 36 | NSString * userName = [SSKeychain passwordForService:[Properties getAPPID] account:USER_NAME]; 37 | NSString * password = [SSKeychain passwordForService:[Properties getAPPID] account:PASSWORD]; 38 | [self login:userName password:password fromKeyChain:YES]; 39 | } 40 | 41 | -(void) login:(NSString *)userName password:(NSString *)password fromKeyChain:(BOOL)fromKC;{ 42 | 43 | NSString *fields = @"name,email"; 44 | NSString *userInfoAPI = [NSString stringWithFormat:@"/api/now/v2/table/sys_user?sysparm_fields=%@&user_name=%@", fields, userName]; 45 | 46 | // Setting up HTTPSession manager for entire app with proper username and password. 47 | AFHTTPSessionManager *manager = [AFHTTPSessionManagerFactory sharedManager]; 48 | [manager.requestSerializer setAuthorizationHeaderFieldWithUsername:userName password:password]; 49 | 50 | [manager GET:userInfoAPI parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { 51 | 52 | // On success store username and password in keychain. Helps in authenticating from keychain later on 53 | 54 | [SSKeychain setPassword:userName 55 | forService: [Properties getAPPID] 56 | account:USER_NAME]; 57 | [SSKeychain setPassword:password 58 | forService:[Properties getAPPID] 59 | account:PASSWORD]; 60 | 61 | // Populate auth session with User Info 62 | [self populateUserSession:responseObject[@"result"][0][@"name"]]; 63 | 64 | 65 | // Notify Users 66 | 67 | if (fromKC) { 68 | [[NSNotificationCenter defaultCenter] postNotificationName:KEYCHAIN_LOGIN_EVENT object: nil]; 69 | } else { 70 | [[NSNotificationCenter defaultCenter] postNotificationName:LOGIN_EVENT object: nil]; 71 | } 72 | 73 | } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { 74 | 75 | [self logout]; 76 | 77 | if (fromKC) { 78 | [[NSNotificationCenter defaultCenter] postNotificationName:KEYCHAIN_LOGIN_EVENT object: nil]; 79 | } else { 80 | [[NSNotificationCenter defaultCenter] postNotificationName:LOGIN_EVENT object: nil]; 81 | } 82 | 83 | }]; 84 | } 85 | 86 | -(void) logout;{ 87 | // Clear out credentials from keychain 88 | [SSKeychain deletePasswordForService:[Properties getAPPID] account:USER_NAME]; 89 | [SSKeychain deletePasswordForService:[Properties getAPPID] account:PASSWORD]; 90 | } 91 | 92 | @end 93 | -------------------------------------------------------------------------------- /MyTasks/LoginViewController.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 ServiceNow, Inc. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions 10 | of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 12 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 13 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 14 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 15 | IN THE SOFTWARE. 16 | */ 17 | 18 | #import "LoginViewController.h" 19 | #import "Properties.h" 20 | #import "Authenticator.h" 21 | #import "AFHTTPSessionManagerFactory.h" 22 | #import "AppDelegate.h" 23 | 24 | 25 | @interface LoginViewController () 26 | @property (weak, nonatomic) IBOutlet UITextField *instanceName; 27 | @property (weak, nonatomic) IBOutlet UITextField *userName; 28 | @property (weak, nonatomic) IBOutlet UITextField *password; 29 | @property (weak, nonatomic) IBOutlet UILabel *errorMsg; 30 | @property (weak, nonatomic) IBOutlet UIButton *login; 31 | @property (weak, nonatomic) IBOutlet UILabel *protocol; 32 | @property (weak, nonatomic) IBOutlet UILabel *domainName; 33 | @property (weak, nonatomic) IBOutlet UILabel *fullHostName; 34 | 35 | @end 36 | 37 | @implementation LoginViewController 38 | 39 | - (void)viewDidLoad { 40 | [super viewDidLoad]; 41 | 42 | // Loading login view: reset error message, logout to clean redundant session data 43 | [self.errorMsg setText:@""]; 44 | UIImage* logoImage = [UIImage imageNamed:@"icon_small.png"]; 45 | self.navigationItem.titleView = [[UIImageView alloc] initWithImage:logoImage]; 46 | 47 | self.navigationItem.hidesBackButton = YES; 48 | self.instanceName.text= [Properties getInstanceName]; 49 | [self setFullHostNameText]; 50 | 51 | _authenticator=[Authenticator sharedAuthenticator]; 52 | [_authenticator logout]; 53 | } 54 | 55 | - (void)didReceiveMemoryWarning { 56 | [super didReceiveMemoryWarning]; 57 | } 58 | 59 | 60 | - (IBAction)login:(id)sender { 61 | if([self.instanceName.text length]==0 || [self.userName.text length]==0 || [self.password.text length]==0){ 62 | [self.errorMsg setText: @"Enter login credentials "]; 63 | } 64 | 65 | // Login button clicked. Start authentication process and wait for login_event ntfcn 66 | [_authenticator authenticate:self.userName.text password:self.password.text]; 67 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loginEventListener:) name:LOGIN_EVENT object:nil]; 68 | } 69 | - (IBAction)instanceNameChanged:(id)sender { 70 | [self setFullHostNameText]; 71 | [Properties setInstanceName:self.instanceName.text]; 72 | } 73 | 74 | - (IBAction)instanceNameValueEdited:(id)sender { 75 | [self setFullHostNameText]; 76 | } 77 | 78 | -(void) setFullHostNameText;{ 79 | if([self.instanceName.text length] ==0) 80 | self.fullHostName.text=[[PROTOCOL stringByAppendingString:@""]stringByAppendingString:DOMAIN_NAME]; 81 | else 82 | self.fullHostName.text=[[PROTOCOL stringByAppendingString:self.instanceName.text]stringByAppendingString:DOMAIN_NAME]; 83 | } 84 | 85 | -(void) loginEventListener:(NSNotification *) ntfcn { 86 | // Handle Login Event. Verify if authentication succeeded and redirect to approapriate view or set appropriate error message 87 | AuthSession *session = [AuthSession sharedSession]; 88 | if([session isAuthenticated]) { 89 | AppDelegate* appDelegate = (AppDelegate*)[[UIApplication sharedApplication]delegate]; 90 | [appDelegate sendDeviceToken]; 91 | UIViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:@"TaskListViewNavController"]; 92 | [self presentViewController:vc animated:YES completion:nil]; 93 | } else { 94 | [self.errorMsg setText:@"Login failed. Check credentials"]; 95 | } 96 | } 97 | 98 | @end 99 | -------------------------------------------------------------------------------- /MyTasks/APIRequestMonitor.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 ServiceNow, Inc. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions 10 | of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 12 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 13 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 14 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 15 | IN THE SOFTWARE. 16 | */ 17 | 18 | 19 | #import "APIRequestMonitor.h" 20 | 21 | @implementation APIRequestMonitor { 22 | BOOL _isMessageViewDisplayed; 23 | } 24 | 25 | + (instancetype) _sharedRequestMonitor { 26 | static APIRequestMonitor *_sharedRequestMonitor = nil; 27 | 28 | static dispatch_once_t onceToken; 29 | dispatch_once(&onceToken, ^{ 30 | _sharedRequestMonitor = [[self alloc] init]; 31 | }); 32 | 33 | return _sharedRequestMonitor; 34 | } 35 | 36 | 37 | - (void)stopMontoring { 38 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 39 | } 40 | 41 | - (void)dealloc { 42 | [self stopMontoring]; 43 | } 44 | 45 | - (void)startMontoring { 46 | [[NSNotificationCenter defaultCenter] addObserver:self 47 | selector:@selector(networkRequestDidStart:) 48 | name:AFNetworkingTaskDidResumeNotification 49 | object:nil]; 50 | 51 | [[NSNotificationCenter defaultCenter] addObserver:self 52 | selector:@selector(networkRequestDidFinish:) 53 | name:AFNetworkingTaskDidCompleteNotification 54 | object:nil]; 55 | } 56 | 57 | - (void) networkRequestDidStart:(NSNotification *)notification { 58 | 59 | UIView *view = [[self topMostController] view]; 60 | 61 | if(_isMessageViewDisplayed){ 62 | return; 63 | } 64 | 65 | _isMessageViewDisplayed = YES; 66 | 67 | self.mask = [[UIView alloc] initWithFrame:[view bounds]]; 68 | self.mask.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.2]; 69 | UIAlertView *loadMessageView = [[UIAlertView alloc] initWithFrame:CGRectMake(0, 0, 170, 170)]; 70 | [self.mask addSubview:loadMessageView]; 71 | loadMessageView.center = view.center; 72 | 73 | loadMessageView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.5]; 74 | loadMessageView.clipsToBounds = YES; 75 | loadMessageView.layer.cornerRadius = 10.0; 76 | 77 | UIActivityIndicatorView *activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; 78 | activityIndicatorView.frame = CGRectMake(65, 40, activityIndicatorView.bounds.size.width, activityIndicatorView.bounds.size.height); 79 | [loadMessageView addSubview:activityIndicatorView]; 80 | [activityIndicatorView startAnimating]; 81 | 82 | UILabel *message = [[UILabel alloc] initWithFrame:CGRectMake(20, 115, 130, 22)]; 83 | message.backgroundColor = [UIColor clearColor]; 84 | message.textColor = [UIColor whiteColor]; 85 | message.adjustsFontSizeToFitWidth = YES; 86 | message.textAlignment = NSTextAlignmentCenter; 87 | message.text = @"Loading..."; 88 | [loadMessageView addSubview:message]; 89 | 90 | [view addSubview:self.mask]; 91 | } 92 | 93 | - (void) networkRequestDidFinish:(NSNotification *)notification { 94 | _isMessageViewDisplayed = NO; 95 | [self.mask removeFromSuperview]; 96 | } 97 | 98 | - (UIViewController*) topMostController 99 | { 100 | return [self topViewController:[UIApplication sharedApplication].keyWindow.rootViewController]; 101 | } 102 | 103 | - (UIViewController *)topViewController:(UIViewController *)rootViewController 104 | { 105 | if (rootViewController.presentedViewController == nil) { 106 | return rootViewController; 107 | } 108 | 109 | if ([rootViewController.presentedViewController isMemberOfClass:[UINavigationController class]]) { 110 | UINavigationController *navigationController = (UINavigationController *)rootViewController.presentedViewController; 111 | UIViewController *lastViewController = [[navigationController viewControllers] lastObject]; 112 | return [self topViewController:lastViewController]; 113 | } 114 | 115 | UIViewController *presentedViewController = (UIViewController *)rootViewController.presentedViewController; 116 | return [self topViewController:presentedViewController]; 117 | } 118 | 119 | @end 120 | -------------------------------------------------------------------------------- /MyTasks/AppDelegate.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 ServiceNow, Inc. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions 10 | of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 12 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 13 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 14 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 15 | IN THE SOFTWARE. 16 | */ 17 | 18 | #import "AppDelegate.h" 19 | #import "AuthSession.h" 20 | #import "AFHTTPSessionManagerFactory.h" 21 | #import "Authenticator.h" 22 | #import "APIRequestMonitor.h" 23 | #import "RestAPIRequestHandler.h" 24 | 25 | @interface AppDelegate () 26 | 27 | @end 28 | 29 | @implementation AppDelegate 30 | 31 | 32 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 33 | // Override point for customization after application launch. 34 | [self initialize]; 35 | 36 | // Register the supported interaction types. 37 | UIUserNotificationType types = UIUserNotificationTypeBadge | 38 | UIUserNotificationTypeSound | UIUserNotificationTypeAlert; 39 | UIUserNotificationSettings *mySettings = 40 | [UIUserNotificationSettings settingsForTypes:types categories:nil]; 41 | [[UIApplication sharedApplication] registerUserNotificationSettings:mySettings]; 42 | 43 | // Register for remote notifications. 44 | [[UIApplication sharedApplication] registerForRemoteNotifications]; 45 | 46 | return YES; 47 | } 48 | 49 | - (void)sendDeviceToken { 50 | RestAPIRequestHandler *apiHandler = [[RestAPIRequestHandler alloc]init]; 51 | 52 | if (deviceToken == nil || [deviceToken isEqual:[NSNull null]]) { 53 | return; 54 | } 55 | 56 | [apiHandler postInstallation:deviceToken success:^(NSDictionary *result) { 57 | NSLog(@"Sent token to Servicenow"); 58 | } failure:^(NSError *error) { 59 | NSLog(@"Error sending token to Servicenow: %@", error); 60 | }]; 61 | } 62 | 63 | - (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken { 64 | // http://stackoverflow.com/q/9372815 65 | NSString * deviceTokenString = [[[[devToken description] 66 | stringByReplacingOccurrencesOfString: @"<" withString: @""] 67 | stringByReplacingOccurrencesOfString: @">" withString: @""] 68 | stringByReplacingOccurrencesOfString: @" " withString: @""]; 69 | 70 | registered = YES; 71 | deviceToken = deviceTokenString; 72 | } 73 | 74 | - (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err { 75 | NSLog(@"Error in registration. Error: %@", err); 76 | } 77 | 78 | - (void)applicationWillResignActive:(UIApplication *)application { 79 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 80 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 81 | } 82 | 83 | - (void)applicationDidEnterBackground:(UIApplication *)application { 84 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 85 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 86 | [[APIRequestMonitor _sharedRequestMonitor] stopMontoring]; 87 | } 88 | 89 | - (void)applicationWillEnterForeground:(UIApplication *)application { 90 | [self initialize]; 91 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 92 | } 93 | 94 | - (void)applicationDidBecomeActive:(UIApplication *)application { 95 | [self initialize]; 96 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 97 | } 98 | 99 | - (void)applicationWillTerminate:(UIApplication *)application { 100 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 101 | [[APIRequestMonitor _sharedRequestMonitor] stopMontoring]; 102 | } 103 | 104 | -(void)initialize;{ 105 | 106 | // [AFHTTPSessionManagerFactory sharedManager]; 107 | 108 | [AuthSession sharedSession]; 109 | 110 | [Authenticator sharedAuthenticator]; 111 | 112 | [[APIRequestMonitor _sharedRequestMonitor] startMontoring]; 113 | 114 | } 115 | 116 | @end 117 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2016 ServiceNow, Inc. 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 5 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 6 | This Software contains the following additional third party packages: 7 | AFNetworking-3.0.0 8 | Copyright (c) 2012 Mattt Thompson (http://mattt.me/) 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in 18 | all copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | THE SOFTWARE. 27 | 28 | ADDITIONAL LICENSE INFORMATION: 29 | 30 | < AFNetworking-3.0.0\AFNetworking\AFHTTPSessionManager.h: 31 | ------------------------------------------------------- 32 | 33 | AFHTTPSessionManager.h 34 | Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/) 35 | 36 | Permission is hereby granted, free of charge, to any person obtaining a copy 37 | of this software and associated documentation files (the "Software"), to deal 38 | in the Software without restriction, including without limitation the rights 39 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 40 | copies of the Software, and to permit persons to whom the Software is 41 | furnished to do so, subject to the following conditions: 42 | 43 | The above copyright notice and this permission notice shall be included in 44 | all copies or substantial portions of the Software. 45 | 46 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 47 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 48 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 49 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 50 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 51 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 52 | THE SOFTWARE. 53 | 54 | < Copyright (c) 2013 AFNetworking (http://afnetworking.com/) 55 | 56 | Permission is hereby granted, free of charge, to any person obtaining a copy 57 | of this software and associated documentation files (the "Software"), to deal 58 | in the Software without restriction, including without limitation the rights 59 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 60 | copies of the Software, and to permit persons to whom the Software is 61 | furnished to do so, subject to the following conditions: 62 | 63 | The above copyright notice and this permission notice shall be included in 64 | all copies or substantial portions of the Software. 65 | 66 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 67 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 68 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 69 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 70 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 71 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 72 | THE SOFTWARE. 73 | ++++++++++++++++++++++++++++++++++++++++++++++++++++ 74 | 75 | SSKeychain-1.4.0 76 | Copyright (c) 2010-2016 Sam Soffes, http://soff.es 77 | 78 | Permission is hereby granted, free of charge, to any person obtaining 79 | a copy of this software and associated documentation files (the 80 | "Software"), to deal in the Software without restriction, including 81 | without limitation the rights to use, copy, modify, merge, publish, 82 | distribute, sublicense, and/or sell copies of the Software, and to 83 | permit persons to whom the Software is furnished to do so, subject to 84 | the following conditions: 85 | 86 | The above copyright notice and this permission notice shall be 87 | included in all copies or substantial portions of the Software. 88 | 89 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 90 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 91 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 92 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 93 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 94 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 95 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 96 | ++++++++++++++++++++++++++++++++++++++++++++++++++++ 97 | 98 | -------------------------------------------------------------------------------- /MyTasks/RestAPIRequestHandler.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 ServiceNow, Inc. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions 10 | of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 12 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 13 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 14 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 15 | IN THE SOFTWARE. 16 | */ 17 | 18 | #import "RestAPIRequestHandler.h" 19 | #import "Properties.h" 20 | #import "AFHTTPSessionManagerFactory.h" 21 | 22 | @implementation RestAPIRequestHandler 23 | 24 | -(id) init;{ 25 | if( self = [super init] ) { 26 | self.manager = [AFHTTPSessionManagerFactory sharedManager]; 27 | } 28 | return self; 29 | } 30 | 31 | -(void) getTaskComments:(NSString*) taskId success: (void (^) (NSArray* result))success failure:(void (^)(NSError* error))failure { 32 | NSString* query = [NSString stringWithFormat: @"element_id=%@^ORDERBYDESCsys_created_on",taskId]; 33 | NSString* limit = @"3"; 34 | NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:query,@"sysparm_query",limit,@"sysparm_limit",nil]; 35 | NSString *endPoint = @"api/now/v2/table/sys_journal_field"; 36 | 37 | [self.manager GET:endPoint parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { 38 | NSDictionary* response = (NSDictionary *)responseObject; 39 | NSArray* comments = response[@"result"]; 40 | success(comments); 41 | } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { 42 | NSLog(@"Request sent with error"); 43 | failure(error); 44 | }]; 45 | } 46 | 47 | -(void) getAssignedTasks:(void (^)(NSDictionary* result))success failure: (void (^) (NSURLSessionDataTask * _Nullable task, NSError* error))failure { 48 | NSString *endPoint = @"api/x_snc_my_work/v1/tracker/task"; 49 | [self.manager GET:endPoint parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { 50 | NSDictionary* response = (NSDictionary *)responseObject; 51 | NSDictionary* result = response[@"result"]; 52 | success(result); 53 | } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { 54 | NSLog(@"Request sent with error"); 55 | failure(task, error); 56 | }]; 57 | } 58 | 59 | -(void) getTaskDetails:(NSString*) taskId success: (void (^) (NSDictionary* result))success failure: (void (^) (NSError* error))failure { 60 | NSString *endPoint = [NSString stringWithFormat: @"api/now/v2/table/task/%@",taskId]; 61 | 62 | [self.manager GET:endPoint parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { 63 | NSDictionary* response = (NSDictionary *)responseObject; 64 | NSDictionary* result = response[@"result"]; 65 | success(result); 66 | } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { 67 | NSLog(@"Request sent with error"); 68 | failure(error); 69 | }]; 70 | } 71 | 72 | -(void) postComment:(NSString*) comment onTask: (NSString*) taskId success: (void (^) (NSDictionary* result))success failure: (void (^) (NSError* error))failure { 73 | NSString* endPoint = [NSString stringWithFormat: @"api/x_snc_my_work/v1/tracker/task/%@/comment",taskId]; 74 | NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:comment,@"comment",nil]; 75 | 76 | [self.manager POST:endPoint parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { 77 | NSDictionary* response = (NSDictionary *)responseObject; 78 | success(response); 79 | } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { 80 | NSLog(@"Request sent with error"); 81 | failure(error); 82 | }]; 83 | } 84 | 85 | -(void) postInstallation:(NSString*) token success: (void (^) (NSDictionary* result))success failure:(void (^)(NSError* error))failure { 86 | NSString* applicationName = @"MyTasks"; 87 | 88 | #define APNS_SANDBOX 1 89 | 90 | #if APNS_SANDBOX 91 | NSString* platform = @"Apple Sandbox"; 92 | NSLog(@"Using APNs sandbox mode"); 93 | #endif 94 | #if !APNS_SANDBOX 95 | NSString* platform = @"Apple"; 96 | #endif 97 | NSString* endPoint = [NSString stringWithFormat: @"api/now/v1/push/%@/installation", applicationName]; 98 | 99 | NSDictionary *params = @ {@"platform" :platform, @"token" :token }; 100 | 101 | [self.manager POST:endPoint 102 | parameters:params 103 | progress:nil 104 | success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { 105 | NSLog(@"Token installed on instance"); 106 | NSDictionary* response = [NSMutableDictionary dictionary]; 107 | if (success) { 108 | success(response); 109 | } 110 | } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { 111 | if (failure) { 112 | failure(error); 113 | } 114 | }]; 115 | } 116 | 117 | @end 118 | -------------------------------------------------------------------------------- /MyTasks/OAuthHandle.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 ServiceNow, Inc. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions 10 | of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 12 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 13 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 14 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 15 | IN THE SOFTWARE. 16 | */ 17 | 18 | #import "OAuthHandle.h" 19 | #import "Properties.h" 20 | #import "AFHTTPSessionManagerFactory.h" 21 | #import "SSKeychain.h" 22 | 23 | #define ACCESS_TOKEN @"access_token" 24 | #define REFRESH_TOKEN @"refresh_token" 25 | #define CLIENT_ID @"client_id" 26 | #define CLIENT_SECRET @"client_secret" 27 | #define EXPIRY_TIME @"expires_in" 28 | #define GRANT_TYPE @"grant_type" 29 | 30 | @implementation OAuthHandle 31 | 32 | 33 | -(id)init;{ 34 | self =[super init]; 35 | 36 | _clientId = [Properties getClientId]; 37 | _clientSecret = [Properties getClientSecret]; 38 | [SSKeychain setPassword:_clientId 39 | forService:[Properties getAPPID] 40 | account:CLIENT_ID]; 41 | [SSKeychain setPassword:_clientSecret 42 | forService:[Properties getAPPID] 43 | account:CLIENT_SECRET]; 44 | 45 | return self; 46 | } 47 | 48 | -(void) authenticate:(NSString *)userName password:(NSString *)password;{ 49 | AFHTTPSessionManager *manager = [AFHTTPSessionManagerFactory sharedManager]; 50 | manager.requestSerializer = [AFHTTPRequestSerializer serializer]; 51 | 52 | NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:@"password",GRANT_TYPE,_clientId,CLIENT_ID, _clientSecret,CLIENT_SECRET, userName, USER_NAME, password, PASSWORD, nil]; 53 | 54 | [manager POST:@"/oauth_token.do" parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { 55 | // On success, save UserName, refresh token, client Id, client secret, expiry time in keychain 56 | NSString *refresh_token = responseObject[REFRESH_TOKEN]; 57 | NSString *expiryTime = responseObject[EXPIRY_TIME]; 58 | NSString *access_token = responseObject[ACCESS_TOKEN]; 59 | 60 | [SSKeychain setPassword:userName 61 | forService: [Properties getAPPID] 62 | account:USER_NAME]; 63 | 64 | [SSKeychain setPassword:refresh_token 65 | forService:[Properties getAPPID] 66 | account:REFRESH_TOKEN]; 67 | 68 | [self saveExpiryTime:expiryTime]; 69 | 70 | [self login:userName accessToken:access_token fromKeyChain:NO]; 71 | } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { 72 | [[NSNotificationCenter defaultCenter] postNotificationName:LOGIN_EVENT object: nil]; 73 | }]; 74 | 75 | } 76 | 77 | - (void)authenticateUsingKeyChain; { 78 | NSString *userName = [SSKeychain passwordForService:[Properties getAPPID] account:USER_NAME]; 79 | NSString *access_token = [SSKeychain passwordForService:[Properties getAPPID] account:ACCESS_TOKEN]; 80 | 81 | NSString *expiryTimeString = [SSKeychain passwordForService:[Properties getAPPID] account:EXPIRY_TIME]; 82 | 83 | NSDateFormatter *formatter = [[NSDateFormatter alloc]init]; 84 | [formatter setDateStyle:NSDateFormatterShortStyle]; 85 | [formatter setTimeStyle:NSDateFormatterFullStyle]; 86 | NSDate *expiryDate = [formatter dateFromString:expiryTimeString]; 87 | 88 | if(NSOrderedDescending ==[expiryDate compare:[NSDate date]]) { 89 | // If not expired, make sys_user call with access token 90 | [self login:userName accessToken:access_token fromKeyChain:YES]; 91 | } else { 92 | AFHTTPSessionManager *manager = [AFHTTPSessionManagerFactory sharedManager]; 93 | manager.requestSerializer = [AFHTTPRequestSerializer serializer]; 94 | 95 | NSString *refresh_token = [SSKeychain passwordForService:[Properties getAPPID] account:REFRESH_TOKEN]; 96 | NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:@"refresh_token",GRANT_TYPE,_clientId,CLIENT_ID, _clientSecret,CLIENT_SECRET, refresh_token, REFRESH_TOKEN, nil]; 97 | 98 | [manager POST:@"/oauth_token.do" parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { 99 | // On success, save UserName, refresh token, client Id, client secret, expiry time in keychain 100 | NSString *refresh_token = responseObject[REFRESH_TOKEN]; 101 | NSString *expiryTime = responseObject[EXPIRY_TIME]; 102 | NSString *access_token = responseObject[ACCESS_TOKEN]; 103 | 104 | [SSKeychain setPassword:userName 105 | forService: [Properties getAPPID] 106 | account:USER_NAME]; 107 | [SSKeychain setPassword:refresh_token 108 | forService:[Properties getAPPID] 109 | account:REFRESH_TOKEN]; 110 | [self saveExpiryTime:expiryTime]; 111 | 112 | [self login:userName accessToken:access_token fromKeyChain:YES]; 113 | 114 | } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { 115 | [[NSNotificationCenter defaultCenter] postNotificationName:KEYCHAIN_LOGIN_EVENT object: nil]; 116 | }]; 117 | } 118 | } 119 | 120 | -(void) login:(NSString *)userName accessToken:(NSString *)accessToken fromKeyChain:(BOOL)fromKC;{ 121 | 122 | 123 | NSString *fields = @"name,email"; 124 | NSString *userInfoAPI = [NSString stringWithFormat:@"/api/now/table/sys_user?sysparm_fields=%@&user_name=%@", fields, userName]; 125 | 126 | // Setting up HTTPSession manager for entire app with proper username and password. 127 | AFHTTPSessionManager *manager = [AFHTTPSessionManagerFactory sharedManager]; 128 | NSString *authHeader = [NSString stringWithFormat: @"Bearer %@", accessToken]; 129 | [manager.requestSerializer setValue:authHeader forHTTPHeaderField:@"Authorization"]; 130 | 131 | [manager GET:userInfoAPI parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { 132 | [SSKeychain setPassword:accessToken 133 | forService: [Properties getAPPID] 134 | account:ACCESS_TOKEN]; 135 | 136 | // Populate auth session with User Info 137 | [self populateUserSession:responseObject[@"result"][0][@"name"]]; 138 | 139 | // Notify Users 140 | 141 | if (fromKC) { 142 | [[NSNotificationCenter defaultCenter] postNotificationName:KEYCHAIN_LOGIN_EVENT object: nil]; 143 | } else { 144 | [[NSNotificationCenter defaultCenter] postNotificationName:LOGIN_EVENT object: nil]; 145 | } 146 | 147 | } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { 148 | 149 | [self logout]; 150 | 151 | if (fromKC) { 152 | [[NSNotificationCenter defaultCenter] postNotificationName:KEYCHAIN_LOGIN_EVENT object: nil]; 153 | } else { 154 | [[NSNotificationCenter defaultCenter] postNotificationName:LOGIN_EVENT object: nil]; 155 | } 156 | }]; 157 | } 158 | 159 | 160 | -(void) logout;{ 161 | // Clear out credentials from keychain 162 | [SSKeychain deletePasswordForService:[Properties getAPPID] account:USER_NAME]; 163 | [SSKeychain deletePasswordForService:[Properties getAPPID] account:ACCESS_TOKEN]; 164 | [SSKeychain deletePasswordForService:[Properties getAPPID] account:REFRESH_TOKEN]; 165 | [SSKeychain deletePasswordForService:[Properties getAPPID] account:EXPIRY_TIME]; 166 | } 167 | 168 | -(void)saveExpiryTime: (NSString *)expiryTime{ 169 | NSDate *mydate = [NSDate date]; 170 | NSDate *expiryDate = [mydate dateByAddingTimeInterval:[expiryTime intValue]]; 171 | NSString *expiryDateString = [NSDateFormatter localizedStringFromDate:expiryDate 172 | dateStyle:NSDateFormatterShortStyle 173 | timeStyle:NSDateFormatterFullStyle]; 174 | 175 | [SSKeychain setPassword:expiryDateString 176 | forService:[Properties getAPPID] 177 | account:EXPIRY_TIME]; 178 | 179 | } 180 | @end 181 | -------------------------------------------------------------------------------- /MyTasks/DetailViewController.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 ServiceNow, Inc. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions 10 | of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 12 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 13 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 14 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 15 | IN THE SOFTWARE. 16 | */ 17 | 18 | #import "DetailViewController.h" 19 | #import "RestAPIRequestHandler.h" 20 | #import "Properties.h" 21 | 22 | @interface DetailViewController () 23 | @property (weak, nonatomic) IBOutlet UITextField *number; 24 | @property (weak, nonatomic) IBOutlet UITextView *shortDescription; 25 | @property (weak, nonatomic) IBOutlet UITextView *comment; 26 | @property (weak, nonatomic) IBOutlet UIBarButtonItem *save; 27 | @property (weak, nonatomic) IBOutlet UITextField *opened; 28 | 29 | @end 30 | 31 | @implementation DetailViewController 32 | 33 | - (void)viewDidLoad { 34 | [super viewDidLoad]; 35 | 36 | self.title=self.item.tableName; 37 | [self retrieveDetail]; 38 | [self getRecentActivity]; 39 | } 40 | 41 | -(void) retrieveDetail;{ 42 | RestAPIRequestHandler *apiHandler = [[RestAPIRequestHandler alloc]init]; 43 | [apiHandler getTaskDetails:self.item.sysId success:^(NSDictionary *result) { 44 | self.item.shortDescription=result[@"short_description"]; 45 | self.item.number=result[@"number"]; 46 | self.item.opened=result[@"sys_created_on"]; 47 | self.number.text= self.item.number; 48 | self.shortDescription.text =self.item.shortDescription; 49 | self.opened.text=self.item.opened; 50 | } failure:^(NSError* error) { 51 | UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Error" message:@"Error retrieving Task details. Retry ?" preferredStyle:UIAlertControllerStyleAlert]; 52 | UIAlertAction* ok = [UIAlertAction 53 | actionWithTitle:@"OK" 54 | style:UIAlertActionStyleDefault 55 | handler:^(UIAlertAction * action) 56 | { 57 | [alert dismissViewControllerAnimated:YES completion:nil]; 58 | [self retrieveDetail]; 59 | }]; 60 | [alert addAction:ok]; 61 | UIAlertAction* cancel = [UIAlertAction 62 | actionWithTitle:@"Cancel" 63 | style:UIAlertActionStyleDefault 64 | handler:^(UIAlertAction * action) 65 | { 66 | [alert dismissViewControllerAnimated:YES completion:nil]; 67 | }]; 68 | [alert addAction:cancel]; 69 | [self presentViewController:alert animated:YES completion:nil]; 70 | }]; 71 | } 72 | 73 | - (void)didReceiveMemoryWarning { 74 | [super didReceiveMemoryWarning]; 75 | // Dispose of any resources that can be recreated. 76 | } 77 | 78 | #pragma mark - Table view data source 79 | 80 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 81 | return 3; 82 | } 83 | 84 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 85 | if(section == 0) 86 | return 2; 87 | else if(section == 1){ 88 | return 1; 89 | } else if(section == 2){ 90 | return 3; 91 | } 92 | return 0; 93 | } 94 | 95 | - (IBAction)save:(id)sender { 96 | NSString *comment = self.comment.text; 97 | RestAPIRequestHandler *apiHandler = [[RestAPIRequestHandler alloc]init]; 98 | [apiHandler postComment:comment onTask:self.item.sysId success:^(NSDictionary *result) { 99 | self.comment.text=@""; 100 | UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Success" message:@"Comment Saved" preferredStyle:UIAlertControllerStyleAlert]; 101 | UIAlertAction* ok = [UIAlertAction 102 | actionWithTitle:@"OK" 103 | style:UIAlertActionStyleDefault 104 | handler:^(UIAlertAction * action) 105 | { 106 | [alert dismissViewControllerAnimated:YES completion:nil]; 107 | }]; 108 | [alert addAction:ok]; 109 | [self presentViewController:alert animated:YES completion:nil]; 110 | [self getRecentActivity]; 111 | } failure:^(NSError* error) { 112 | UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Error" message:@"Error saving comments. Retry ?" preferredStyle:UIAlertControllerStyleAlert]; 113 | UIAlertAction* ok = [UIAlertAction 114 | actionWithTitle:@"OK" 115 | style:UIAlertActionStyleDefault 116 | handler:^(UIAlertAction * action) 117 | { 118 | [alert dismissViewControllerAnimated:YES completion:nil]; 119 | [self save]; 120 | }]; 121 | [alert addAction:ok]; 122 | UIAlertAction* cancel = [UIAlertAction 123 | actionWithTitle:@"Cancel" 124 | style:UIAlertActionStyleDefault 125 | handler:^(UIAlertAction * action) 126 | { 127 | [alert dismissViewControllerAnimated:YES completion:nil]; 128 | }]; 129 | [alert addAction:cancel]; 130 | [self presentViewController:alert animated:YES completion:nil]; 131 | }]; 132 | } 133 | 134 | -(void)getRecentActivity;{ 135 | RestAPIRequestHandler *apiHandler = [[RestAPIRequestHandler alloc]init]; 136 | [apiHandler getTaskComments:self.item.sysId success:^(NSArray *response) { 137 | for (int i=0; i<[response count]; i++) { 138 | NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:2]; 139 | UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath]; 140 | 141 | [cell initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:nil]; 142 | 143 | NSString *cellValue = response[i][@"value"]; 144 | NSString *createdOn = response[i][@"sys_created_on"]; 145 | NSString *createdBy = response[i][@"sys_created_by"]; 146 | cell.textLabel.text = cellValue; 147 | 148 | NSMutableParagraphStyle *subtitleParagraphStyle = [NSMutableParagraphStyle new]; 149 | subtitleParagraphStyle.minimumLineHeight = 5; 150 | subtitleParagraphStyle.lineSpacing = 0.3; 151 | subtitleParagraphStyle.minimumLineHeight = 0.4f; 152 | NSString *desc = [NSString stringWithFormat:@"%@, %@", createdBy, createdOn] ; 153 | NSMutableAttributedString *subText = [[[NSAttributedString alloc] initWithString:desc] mutableCopy]; 154 | [subText addAttribute:NSParagraphStyleAttributeName value:subtitleParagraphStyle range:NSMakeRange(0, subText.length)]; 155 | cell.detailTextLabel.attributedText = subText; 156 | cell.detailTextLabel.numberOfLines = 3; 157 | cell.detailTextLabel.lineBreakMode = NSLineBreakByWordWrapping; 158 | } 159 | } failure:^(NSError* error) { 160 | UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Error" message:@"Error retrieving recent activity" preferredStyle:UIAlertControllerStyleAlert]; 161 | UIAlertAction* ok = [UIAlertAction 162 | actionWithTitle:@"OK" 163 | style:UIAlertActionStyleDefault 164 | handler:^(UIAlertAction * action) 165 | { 166 | [alert dismissViewControllerAnimated:YES completion:nil]; 167 | }]; 168 | [alert addAction:ok]; 169 | [self presentViewController:alert animated:YES completion:nil]; 170 | } 171 | ]; 172 | } 173 | 174 | /* 175 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 176 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:<#@"reuseIdentifier"#> forIndexPath:indexPath]; 177 | 178 | // Configure the cell... 179 | 180 | return cell; 181 | } 182 | */ 183 | 184 | /* 185 | // Override to support conditional editing of the table view. 186 | - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { 187 | // Return NO if you do not want the specified item to be editable. 188 | return YES; 189 | } 190 | */ 191 | 192 | /* 193 | // Override to support editing the table view. 194 | - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { 195 | if (editingStyle == UITableViewCellEditingStyleDelete) { 196 | // Delete the row from the data source 197 | [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; 198 | } else if (editingStyle == UITableViewCellEditingStyleInsert) { 199 | // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view 200 | } 201 | } 202 | */ 203 | 204 | /* 205 | // Override to support rearranging the table view. 206 | - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath { 207 | } 208 | */ 209 | 210 | /* 211 | // Override to support conditional rearranging of the table view. 212 | - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { 213 | // Return NO if you do not want the item to be re-orderable. 214 | return YES; 215 | } 216 | */ 217 | 218 | /* 219 | #pragma mark - Navigation 220 | 221 | // In a storyboard-based application, you will often want to do a little preparation before navigation 222 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 223 | // Get the new view controller using [segue destinationViewController]. 224 | // Pass the selected object to the new view controller. 225 | } 226 | */ 227 | 228 | @end 229 | -------------------------------------------------------------------------------- /MyTasks/TaskListViewController.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 ServiceNow, Inc. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions 10 | of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 12 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 13 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 14 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 15 | IN THE SOFTWARE. 16 | */ 17 | 18 | #import "TaskListViewController.h" 19 | #import "DetailViewController.h" 20 | #import "AuthSession.h" 21 | #import "Properties.h" 22 | #import "RestAPIRequestHandler.h" 23 | 24 | 25 | @interface TaskListViewController (){ 26 | NSMutableSet* _collapsedSections; 27 | } 28 | @property (weak, nonatomic) IBOutlet UIBarButtonItem *logoutBtn; 29 | 30 | @end 31 | 32 | @implementation TaskListViewController 33 | 34 | - (void)viewDidLoad { 35 | [super viewDidLoad]; 36 | self.title = @"My Tasks"; 37 | _collapsedSections = [NSMutableSet new]; 38 | [self retrieveTasks]; 39 | } 40 | 41 | - (void)didReceiveMemoryWarning { 42 | [super didReceiveMemoryWarning]; 43 | // Dispose of any resources that can be recreated. 44 | } 45 | 46 | 47 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 48 | return self.sections.count; 49 | } 50 | 51 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 52 | NSString *sectionName = [self.sections objectAtIndex:section]; 53 | NSArray *recordsForSection = [self.result objectForKey:sectionName]; 54 | return [_collapsedSections containsObject:@(section)] ? 0 : [recordsForSection count]; 55 | } 56 | 57 | 58 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 59 | static NSString *CellIdentifier = @"Cell Identifier"; 60 | [tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:CellIdentifier]; 61 | 62 | UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; 63 | 64 | NSString *section = [self.sections objectAtIndex:indexPath.section]; 65 | 66 | NSArray *records = [self.result objectForKey:section]; 67 | NSDictionary *record = [records objectAtIndex:indexPath.row]; 68 | 69 | NSMutableParagraphStyle *subtitleParagraphStyle = [NSMutableParagraphStyle new]; 70 | subtitleParagraphStyle.minimumLineHeight = 5; 71 | subtitleParagraphStyle.lineSpacing = 0.3; 72 | subtitleParagraphStyle.minimumLineHeight = 0.4f; 73 | 74 | NSString *desc = [record objectForKey:@"short_desc"]; 75 | if(![desc isEqual:[NSNull null]]){ 76 | NSMutableAttributedString *subText = [[[NSAttributedString alloc] initWithString:desc] mutableCopy]; 77 | [subText addAttribute:NSParagraphStyleAttributeName value:subtitleParagraphStyle range:NSMakeRange(0, subText.length)]; 78 | cell.detailTextLabel.attributedText = subText; 79 | cell.detailTextLabel.numberOfLines = 3; 80 | cell.detailTextLabel.lineBreakMode = NSLineBreakByWordWrapping; 81 | } 82 | 83 | 84 | 85 | NSString *number = [record objectForKey:@"number"]; 86 | cell.textLabel.text = number; 87 | 88 | self.tableView.rowHeight = 80.0; 89 | 90 | 91 | cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 92 | 93 | 94 | return cell; 95 | } 96 | 97 | - (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath: 98 | (NSIndexPath *)indexPath { 99 | 100 | [self tableView:tableView didSelectRowAtIndexPath:indexPath]; 101 | } 102 | 103 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 104 | DetailViewController *infoController = [self.storyboard instantiateViewControllerWithIdentifier:@"DetailViewController"]; 105 | 106 | NSString *section = [self.sections objectAtIndex:indexPath.section]; 107 | NSArray *records = [self.result objectForKey:section]; 108 | NSDictionary *record = [records objectAtIndex:indexPath.row]; 109 | 110 | TaskItem *item = [[TaskItem alloc]init]; 111 | item.tableName = section; 112 | item.sysId = [record objectForKey:@"sys_id"]; 113 | infoController.item = item; 114 | [self.navigationController pushViewController: infoController animated: YES]; 115 | } 116 | 117 | - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section 118 | { 119 | NSString *sectionTitle = [self.sections objectAtIndex:section]; 120 | return sectionTitle; 121 | } 122 | 123 | -(NSArray*) indexPathsForSection:(int)section withNumberOfRows:(int)numberOfRows { 124 | NSMutableArray* indexPaths = [NSMutableArray new]; 125 | for (int i = 0; i < numberOfRows; i++) { 126 | NSIndexPath* indexPath = [NSIndexPath indexPathForRow:i inSection:section]; 127 | [indexPaths addObject:indexPath]; 128 | } 129 | return indexPaths; 130 | } 131 | 132 | -(void)sectionAccordion:(UITapGestureRecognizer*)sender { 133 | [self.tableView beginUpdates]; 134 | int section = sender.view.tag; 135 | 136 | bool shouldCollapse = ![_collapsedSections containsObject:@(section)]; 137 | if (shouldCollapse) { 138 | int numOfRows = [self.tableView numberOfRowsInSection:section]; 139 | NSArray* indexPaths = [self indexPathsForSection:section withNumberOfRows:numOfRows]; 140 | [self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade]; 141 | [_collapsedSections addObject:@(section)]; 142 | if([sender.view isKindOfClass:[UIButton class]]) { 143 | UIButton *button = (UIButton *) sender.view; 144 | [UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationOptionTransitionNone animations:^ 145 | { 146 | CGAffineTransform transform = button.imageView.transform; 147 | CGAffineTransform transform_new = CGAffineTransformRotate(transform, M_PI); 148 | button.imageView.transform = transform_new; 149 | } completion:NULL]; 150 | } 151 | } else { 152 | NSString *sectionName = [self.sections objectAtIndex:section]; 153 | NSArray *recordsForSection = [self.result objectForKey:sectionName]; 154 | int numRows = [recordsForSection count]; 155 | NSArray* indexPaths = [self indexPathsForSection:section withNumberOfRows:numRows]; 156 | [self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade]; 157 | [_collapsedSections removeObject:@(section)]; 158 | if([sender.view isKindOfClass:[UIButton class]]){ 159 | UIButton *button = (UIButton *) sender.view; 160 | [UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationOptionTransitionNone animations:^ 161 | { 162 | CGAffineTransform transform = button.imageView.transform; 163 | CGAffineTransform transform_new = CGAffineTransformRotate(transform, M_PI); 164 | button.imageView.transform = transform_new; 165 | } completion:NULL]; 166 | } 167 | } 168 | [self.tableView endUpdates]; 169 | } 170 | 171 | -(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { 172 | UITableViewHeaderFooterView *sectionView = [[UITableViewHeaderFooterView alloc]init]; 173 | 174 | UIButton *button = [[UIButton alloc]init]; 175 | [[button imageView] setContentMode:UIViewContentModeScaleAspectFill]; 176 | 177 | UIImage *btnImage = [UIImage imageNamed:@"up.png"]; 178 | [button setImage:btnImage forState:UIControlStateNormal]; 179 | button.translatesAutoresizingMaskIntoConstraints = NO; 180 | [sectionView.contentView addSubview:button]; 181 | [button.trailingAnchor constraintEqualToAnchor:sectionView.trailingAnchor].active = YES; 182 | [button.bottomAnchor constraintEqualToAnchor:sectionView.bottomAnchor].active = YES; 183 | 184 | UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(sectionAccordion:)]; 185 | button.tag=section; 186 | [button addGestureRecognizer:tapGesture]; 187 | return sectionView; 188 | } 189 | 190 | -(void)retrieveTasks; { 191 | RestAPIRequestHandler *apiHandler = [[RestAPIRequestHandler alloc]init]; 192 | [apiHandler getAssignedTasks:^(NSDictionary *result) { 193 | self.sections = [[result allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)]; 194 | if([self.sections count] ==0){ 195 | UIView *view = self.view; 196 | 197 | UIView *msgView = [[UIView alloc] initWithFrame:[view bounds]]; 198 | msgView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.2]; 199 | 200 | UILabel *message = [[UILabel alloc] initWithFrame:[view bounds]]; 201 | message.backgroundColor = [UIColor whiteColor]; 202 | message.textColor = [UIColor blackColor]; 203 | message.adjustsFontSizeToFitWidth = YES; 204 | message.textAlignment = NSTextAlignmentCenter; 205 | message.text = @"Nice Job!. It looks like you dont have any tasks in your queue"; 206 | [msgView addSubview:message]; 207 | [view addSubview:msgView]; 208 | } 209 | self.result = result; 210 | [self.tableView reloadData]; 211 | } failure:^(NSURLSessionDataTask * _Nullable task, NSError *error) { 212 | UIAlertController *alert = nil; 213 | NSHTTPURLResponse* response = (NSHTTPURLResponse*)task.response; 214 | if(response.statusCode == 400) { 215 | alert = [UIAlertController alertControllerWithTitle:@"Error" message:@"The Task Tracker API is not found on this instance. Did you install the \"My Work\" Update Set?" preferredStyle:UIAlertControllerStyleAlert]; 216 | UIAlertAction* ok = [UIAlertAction 217 | actionWithTitle:@"OK" 218 | style:UIAlertActionStyleDefault 219 | handler:^(UIAlertAction * action) 220 | { 221 | [alert dismissViewControllerAnimated:YES completion:nil]; 222 | }]; 223 | [alert addAction:ok]; 224 | } else { 225 | alert = [UIAlertController alertControllerWithTitle:@"Error" message:@"Error sending request. Retry ?" preferredStyle:UIAlertControllerStyleAlert]; 226 | UIAlertAction* ok = [UIAlertAction 227 | actionWithTitle:@"OK" 228 | style:UIAlertActionStyleDefault 229 | handler:^(UIAlertAction * action) 230 | { 231 | [alert dismissViewControllerAnimated:YES completion:nil]; 232 | [self retrieveTasks]; 233 | }]; 234 | [alert addAction:ok]; 235 | UIAlertAction* cancel = [UIAlertAction 236 | actionWithTitle:@"Cancel" 237 | style:UIAlertActionStyleDefault 238 | handler:^(UIAlertAction * action) 239 | { 240 | [alert dismissViewControllerAnimated:YES completion:nil]; 241 | }]; 242 | [alert addAction:cancel]; 243 | } 244 | if(alert != nil) { 245 | [self presentViewController:alert animated:YES completion:nil]; 246 | } 247 | }]; 248 | } 249 | 250 | @end 251 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Example REST Client My Work App: iOS 2 | This project contains source code for a native [iOS](https://developer.apple.com/ios/) application that interacts with ServiceNow's [REST APIs](https://docs.servicenow.com/bundle/helsinki-servicenow-platform/page/integrate/inbound_rest/concept/c_RESTAPI.html) including a [Scripted REST API](https://docs.servicenow.com/bundle/helsinki-servicenow-platform/page/integrate/custom_web_services/concept/c_CustomWebServices.html). The simple use case is a "MyWork" application which displays a user's current tasks and allows comments to be added. This application demonstrates how to build the MyWork app using iOS. To see the same use case implemented in Node.js, see [Example REST Client My Work App: Node.js](https://github.com/ServiceNow/example-restclient-myworkapp-nodejs). 3 | 4 | ## Architecture 5 | Here is an overview of the MyWork application architecture. Note both this iOS application and the Node.js application are represented in the diagram. 6 | ![Architecture diagram](/images/arch_diagram.jpg "Architecture diagram") 7 | 8 | --------------------------------------------------------------------------- 9 | 10 | ## Prerequisites 11 | * OS X [Xcode 7.3.1](https://developer.apple.com/download/more/) installed 12 | * A ServiceNow instance ([Geneva Patch 3](https://docs.servicenow.com/bundle/geneva-release-notes/page/c2/geneva-patch-3-2.html) or later). 13 | * **Don't have a ServiceNow instance?** Get one **FREE** by signing up at https://developer.servicenow.com 14 | * Not sure what version of ServiceNow your instance is running? [Determine running version](http://wiki.servicenow.com/index.php?title=Upgrades_Best_Practices#Prepare_for_Upgrading) 15 | 16 | -------------------------------------------------------------------------- 17 | 18 | ## Setup the iOS project on your machine 19 | 1. Clone the project and install dependencies 20 | * Git clone 21 | ```bash 22 | $ git clone https://github.com/ServiceNow/example-restclient-myworkapp-ios.git 23 | $ cd example-restclient-myworkapp-ios 24 | $ sudo gem install cocoapods 25 | $ pod install 26 | ``` 27 | --or-- 28 | * [Download](https://github.com/ServiceNow/example-restclient-myworkapp-ios/archive/master.zip) the full project as a Zip file 29 | ```bash 30 | 31 | $ cd example-restclient-myworkapp-ios 32 | $ sudo gem install cocoapods 33 | $ pod install 34 | ``` 35 | 36 | * **NOTE:** **pod install** requires permission to modify project directory. In case you run into issues doing the pod install modify permissions to the project directory by running 37 | ```bash 38 | sudo chown -R '[username]' ~/example-restclient-myworkapp-ios 39 | ``` 40 | Make sure the **MyTasks.xcworkspace** file was generated within xcode project directory. 41 | 42 | 2. Install the **MyWork Update Set** in your ServiceNow instance. This is a ServiceNow scoped application which contains the **Task Tracker API** Scripted REST API and related files. Note that you must have the admin role on your ServiceNow instance to install update sets. 43 | 1. Obtain the "My Work" update set 44 | * Download the update set from [share.servicenow.com](https://share.servicenow.com/app.do#/detailV2/e43cf2f313de5600e77a36666144b0b4/overview) 45 |
--or-- 46 | * Get the update set from the directory where you cloned the GitHub repository: **example-restclient-myworkapp-ios/mywork_update_set/sys_remote_update_set_2f48a7d74f4652002fa02f1e0210c785.xml** 47 | 2. Install the Update Set XML 48 | 1. In your ServiceNow instance, navigate to **Retrieved Update Sets** 49 | 2. Click **Import Update Set from XML** 50 | 3. Click **Choose File**, browse to find the downloaded update set XML file from Step 1, and click **Upload** 51 | 4. Click to open the **My Work** update set 52 | 5. Click **Preview Update Set** 53 | 6. Click **Commit Update Set** 54 | 3. Verify the MyWork Update Set installed using the API Explorer 55 | 1. In your ServiceNow instance, navigate to **Scripted REST APIs** 56 | 2. Open the **Task Tracker** Scripted REST API, then open the **My Tasks** API resource 57 | 3. Click **Explore REST API** (this opens the API in the REST API Explorer) 58 | 4. In the API Explorer, click **Send** and verify the API request is sent and receives a **200-OK** response 59 | 60 | -------------------------------------------------------------------------- 61 | 62 | ## Loading & running the iOS application in **XCode** 63 | * Open **`MyTasks.xcworkspace`** with **XCode**. 64 | ![My_Tasks_workspace file](/images/pod_install_result.png) 65 | * To run the project, click the "play" button to build and run the application. 66 | 67 | ![Build and run](/images/build_and_run.png) 68 | 69 | -------------------------------------------------------------------------- 70 | 71 | ## About the application 72 | This is a native iOS application which makes HTTP calls to the **Task Tracker** Scripted REST API to get the list of tasks assigned to the logged-in user and to allow the user to add comments. 73 | 74 | ### Functional flow 75 | 76 | #### 1. Login 77 | The app tries to login using previous authentication information stored in the iOS Keychain. If not available, the app displays the login screen. 78 | 79 | ![Login](/images/login.png) 80 | 81 | The login screen prompts you to input your ServiceNow instance name. For example, if your instance URL is https://myinstance.service-now.com, then enter `myinstance` into the Instance text box. 82 | 83 | Enter the user ID and password for a user on the instance. This application uses Basic Authentication to manage user authentication with the ServiceNow REST API. When a user enters credentials, an HTTP GET call is made to retrieve the user account from the `sys_user` table using the REST Table API. This call establishes a session with the ServiceNow instance. 84 | 85 | On successful login the app stores authentication info (instance, username, and password) into the iOS keychain and then transitions to the task list view. On login failure, the user is directed to the login screen to reenter credentials. 86 | 87 | After login, the application displays the tasks assigned to the user grouped by task type. The application uses the **Task Tracker API** to retrieve the list of tasks from ServiceNow. The logged in user must have access to view the tasks (such as Incidents, Problems, Tickets) for those tasks to be returned in the REST API and subsequently displayed in the 'MyWork App'. 88 | 89 | **> REST API Call:** Get user details (Table API) 90 | ``` 91 | GET /api/now/v2/table/sys_user?user_name=john.doe 92 | ``` 93 | 94 | #### 2. View my tasks 95 | ![Task List](/images/task_list.png) 96 | 97 | Click an item in the list to open the task details. 98 | 99 | **> REST API Call:** Get my tasks (Task Tracker API) 100 | ``` 101 | GET /api/x_snc_my_work/v1/tracker/task 102 | ``` 103 | 104 | #### 3. View task detail/add comment 105 | ![Task Details](/images/task_detail.png) 106 | 107 | Comments can be added to a task and will appear on the work notes for the task both in this application as well as within ServiceNow. 108 | 109 | **> REST API Calls:** Get comments, Add comment (Task Tracker API, Table API) 110 | ``` 111 | GET /api/now/v2/table/sys_journal_field?element_id= 112 | 113 | POST /api/x_snc_my_work/v1/tracker/task/{task_id}/comment 114 | {"comment":"Hello, world!"} 115 | ``` 116 | 117 | ### Application Flow Detail 118 | ![App Flow](/images/node_flow.png) 119 | 120 | #### Modules 121 | * Reusable event based Authentication Module. 122 | * Callback API module to communicate with ServiceNow REST APIs. 123 | * View to show tasks assigned to the logged-in user and to pose comments to tasks. 124 | 125 | ##### Authentication module 126 | The `Authenticator` and `AuthSession` object singletons are provided to encapsulate the authentication mechanism. 127 | * `AuthSession` holds authenticated user info such as name and can be used to see if session is authenticated. 128 | * `Authenticator` 129 | * Exposes two messages (functions) to authenticate using username, password or keychain values: `authenticate` and `authenticateFromKeychain` 130 | * By default is configured to do BasicAuth but can be modified to use OAuth 2.0 password flow. Note you would need to configure the OAuth provider on the instance including setting up a client ID and client secret. 131 | * Dispatches two events, `login_event` or `ks_login_event` on completion of authentication. Callers can listen to these events and act on them. 132 | 133 | ##### RESTAPIRequestHandler 134 | Encapsulates all REST API calls required by views to retrieve task list, retrieve task details and save task comments. 135 | This uses `AFHTTPSessionManagerFactory` to get an `AFHTTPSessionManager`, which is used to make HTTP calls. `AFHttpSessionManager` manages the session by using session cookies stored after the initial successful REST API request. 136 | 137 | ##### Story board, Views and View controllers 138 | * Views 139 | * LoginProgress 140 | * LoginView 141 | * TaskListView 142 | * DetailView 143 | * View Controllers 144 | * LoginProgressView 145 | * LoginView 146 | * TaskListView 147 | * DetailView 148 | * View controllers control the flow of views. 149 | * The LoginProgressView and LoginView controllers use the Authenticator module while the TaskListView and DetailView controllers use the API Module (RESTAPIRequestHandler). 150 | 151 | ##### Quirks 152 | For testing purposes, the App Transport settings have been configured to accept all HTTPS interaction without adding certificates from ServiceNow. In a production application, we wouldn't do this. 153 | 154 | -------------------------------------------------------------------------- 155 | 156 | ## Sample REST API requests/responses 157 | 158 | ### 1. Login/retrieve user account 159 | The initial request to ServiceNow submits the user credentials and retrieves the user account. This establishes a session with ServiceNow which can be maintained by saving and resending the cookies returned from the first request. 160 | 161 | Here is an equivalent sample curl request. It saves the response cookies in a new file called cookies.txt. The same file is specified on subsequent request in order to apply all cookies. 162 | ``` 163 | $ curl --verbose --request GET \ 164 | --header "Accept: application/json" \ 165 | --user "john.doe:password" --cookie cookies.txt --cookie-jar cookies.txt \ 166 | "https://myinstance.service-now.com/api/now/v2/table/sys_user?user_name=john.doe&sysparm_fields=user_name,first_name,last_name,sys_id" 167 | 168 | > GET /api/now/v2/table/sys_user?user_name=john.doe&sysparm_fields=user_name,first_name,last_name,sys_id HTTP/1.1 169 | > Authorization: Basic am9obi5kb2U6cGFzc3dvcmQ= 170 | > Host: myinstance.service-now.com 171 | > Accept: application/json 172 | 173 | < HTTP/1.1 200 OK 174 | < Set-Cookie: JSESSIONID=3BFF4F3A8AC5F4695E0477F6F8E34BDE;Secure; Path=/; HttpOnly 175 | < Set-Cookie: glide_user="";secure; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/; HttpOnly 176 | < Set-Cookie: glide_user_session="";secure; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/; HttpOnly 177 | < Set-Cookie: glide_user_route=glide.787db27f9eb4d8275f143168c5481c86;secure; Expires=Mon, 27-Mar-2084 19:32:44 GMT; Path=/; HttpOnly 178 | < Set-Cookie: glide_session_store=292391354F4212008A5AB895F110C722; Expires=Wed, 09-Mar-2016 16:48:37 GMT; Path=/; HttpOnly 179 | < Set-Cookie: BIGipServerpool_myinstance=2927640842.52542.0000; path=/ 180 | < X-Total-Count: 1 181 | < Pragma: no-store,no-cache 182 | < Cache-control: no-cache,no-store,must-revalidate,max-age=-1 183 | < Expires: 0 184 | < Content-Type: application/json;charset=UTF-8 185 | < Transfer-Encoding: chunked 186 | { 187 | "result": [ 188 | { 189 | "first_name": "John", 190 | "last_name": "Doe", 191 | "sys_id": "ea2bc1b14f4212008a5ab895f110c7d1", 192 | "user_name": "john.doe" 193 | } 194 | ] 195 | } 196 | ``` 197 | 198 | ### 2. Get user's tasks 199 | Next, the user's tasks are retrieved. Note how the cookies from the first request are sent with subsequent requests, and user credentials no longer need to be sent: 200 | ``` 201 | $ curl --verbose --request GET \ 202 | --header "Accept: application/json" \ 203 | --cookie cookies.txt --cookie-jar cookies.txt \ 204 | "https://myinstance.service-now.com/api/x_snc_my_work/v1/tracker/task" 205 | 206 | > GET /api/x_snc_my_work/v1/tracker/task HTTP/1.1 207 | > Host: myinstance.service-now.com 208 | > Cookie: BIGipServerpool_myinstance=2927640842.52542.0000; JSESSIONID=3BFF4F3A8AC5F4695E0477F6F8E34BDE; glide_session_store=292391354F4212008A5AB895F110C722; glide_user_route=glide.787db27f9eb4d8275f143168c5481c86 209 | > Accept: application/json 210 | 211 | < HTTP/1.1 200 OK 212 | < Set-Cookie: glide_user="U0N2Mjo1ODczMTEzNTIxNDIxMjAwOWE3NDgyZDFlZjg3Mzk4OQ==";Secure; Version=1; Max-Age=2147483647; Expires=Mon, 27-Mar-2084 19:34:00 GMT; Path=/; HttpOnly 213 | < Set-Cookie: glide_user_session="U0N2Mjo1ODczMTEzNTIxNDIxMjAwOWE3NDgyZDFlZjg3Mzk4OQ==";Secure; Version=1; Path=/; HttpOnly 214 | < Set-Cookie: glide_session_store=292391354F4212008A5AB895F110C722; Expires=Wed, 09-Mar-2016 16:24:53 GMT; Path=/; HttpOnly 215 | < Pragma: no-store,no-cache 216 | < Cache-control: no-cache,no-store,must-revalidate,max-age=-1 217 | < Expires: 0 218 | < Content-Type: application/json;charset=UTF-8 219 | < Transfer-Encoding: chunked 220 | { 221 | "result": { 222 | "Incident": [ 223 | { 224 | "short_desc": "my computer doesn't work", 225 | "snowui": "https://myinstance.service-now.com/incident.do?sys_id=061c92d26f030200d7aecd9c5d3ee4f8", 226 | "number": "INC0010021", 227 | "sys_id": "061c92d26f030200d7aecd9c5d3ee4f8", 228 | "link": "https://myinstance.service-now.com/api/now/v2/table/incident/061c92d26f030200d7aecd9c5d3ee4f8", 229 | "created": "2015-10-14 07:45:55" 230 | } 231 | ], 232 | "Problem": [ 233 | { 234 | "short_desc": "Unknown source of outage", 235 | "snowui": "https://myinstance.service-now.com/problem.do?sys_id=d7296d02c0a801670085e737da016e70", 236 | "number": "PRB0000011", 237 | "sys_id": "d7296d02c0a801670085e737da016e70", 238 | "link": "https://myinstance.service-now.com/api/now/v2/table/problem/d7296d02c0a801670085e737da016e70", 239 | "created": "2014-02-04 04:58:15" 240 | }, 241 | { 242 | "short_desc": "Getting NPE stack trace accessing link", 243 | "snowui": "https://myinstance.service-now.com/problem.do?sys_id=fb9620914fc212008a5ab895f110c7c4", 244 | "number": "PRB0040010", 245 | "sys_id": "fb9620914fc212008a5ab895f110c7c4", 246 | "link": "https://myinstance.service-now.com/api/now/v2/table/problem/fb9620914fc212008a5ab895f110c7c4", 247 | "created": "2016-03-07 23:47:43" 248 | } 249 | ] 250 | } 251 | } 252 | ``` 253 | 254 | ### 3. Add a comment 255 | To add a comment, send a POST request with a JSON payload using the Task Tracker API. 256 | 257 | ``` 258 | $ curl --verbose --request POST \ 259 | --header "Accept: application/json" --header "Content-Type: application/json" \ 260 | --cookie cookies.txt --cookie-jar cookies.txt \ 261 | --data '{"comment":"Hello, world!"}' \ 262 | "https://myinstance.service-now.com/api/x_snc_my_work/v1/tracker/task/d7296d02c0a801670085e737da016e70/comment" 263 | 264 | > POST /api/x_snc_my_work/v1/tracker/task/d7296d02c0a801670085e737da016e70/comment HTTP/1.1 265 | > Host: myinstance.service-now.com 266 | > Cookie: BIGipServerpool_myinstance=2927640842.52542.0000; JSESSIONID=3BFF4F3A8AC5F4695E0477F6F8E34BDE; glide_session_store=292391354F4212008A5AB895F110C722; glide_user="U0N2Mjo1ODczMTEzNTIxNDIxMjAwOWE3NDgyZDFlZjg3Mzk4OQ=="; glide_user_route=glide.787db27f9eb4d8275f143168c5481c86; glide_user_session="U0N2Mjo1ODczMTEzNTIxNDIxMjAwOWE3NDgyZDFlZjg3Mzk4OQ==" 267 | > Accept: application/json 268 | > Content-Type: application/json 269 | > Content-Length: 27 270 | {"comment":"Hello, world!"} 271 | 272 | < HTTP/1.1 201 Created 273 | < Set-Cookie: glide_session_store=292391354F4212008A5AB895F110C722; Expires=Wed, 09-Mar-2016 16:29:58 GMT; Path=/; HttpOnly 274 | < Content-Type: application/json 275 | < Transfer-Encoding: chunked 276 | { 277 | "data": "Successfully inserted" 278 | } 279 | ``` 280 | -------------------------------------------------------------------------------- /mywork_update_set/sys_remote_update_set_2f48a7d74f4652002fa02f1e0210c785.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11e9a50b4f0a12002fa02f1e0210c737 5 | My Work 6 | x_snc_my_work 7 | 2.0.0 8 | 9 | 10 | 11 | 12 | 13 | My Work 14 | 15 | 16 | f94867d74f4652002fa02f1e0210c735 17 | loaded 18 | 19 | admin 20 | 2016-03-14 19:01:11 21 | 2f48a7d74f4652002fa02f1e0210c785 22 | 0 23 | admin 24 | 2016-03-14 19:01:11 25 | 26 | 27 | 28 | 29 | 30 | INSERT_OR_UPDATE 31 | 11e9a50b4f0a12002fa02f1e0210c737 32 | customer 33 | 34 | sys_script_include_4b43f5034f4a12002fa02f1e0210c7c5 35 | <?xml version="1.0" encoding="UTF-8"?><record_update table="sys_script_include"><sys_script_include action="INSERT_OR_UPDATE"><access>package_private</access><active>true</active><api_name>x_snc_my_work.TaskRetriever</api_name><client_callable>false</client_callable><description>Reusable logic to retrieve tasks</description><name>TaskRetriever</name><script><![CDATA[var TaskRetriever = Class.create(); 36 | TaskRetriever.prototype = { 37 | initialize: function() { 38 | }, 39 | getTaskCount:function(userId, tableName){ 40 | var gr = new GlideRecordSecure(tableName); 41 | gr.addQuery('assigned_to', userId); 42 | gr.addQuery('active', true); 43 | gr.query(); 44 | return gr.getRowCount(); 45 | }, 46 | getTaskRecordsForUser:function(userId){ 47 | var gr = new GlideRecordSecure('task'); 48 | gr.addQuery('assigned_to', userId); 49 | gr.addQuery('active', true); 50 | gr.orderBy('sys_created_on'); 51 | gr.query(); 52 | return gr; 53 | }, 54 | getTaskRecordsForTeam:function(teamName){ 55 | var rec = new GlideRecord("sys_user_group"); 56 | rec.addQuery("name",teamName); 57 | rec.query(); 58 | rec.next(); 59 | var grpId = rec.getValue("sys_id"); 60 | var gr = new GlideRecordSecure('task'); 61 | gr.addQuery('assignment_group', grpId); 62 | gr.addQuery('active', true); 63 | gr.orderBy('sys_created_on'); 64 | gr.query(); 65 | return gr; 66 | }, 67 | populateResponse:function(taskRecs){ 68 | var resp={}; 69 | while (taskRecs.next()) { 70 | var clazz = taskRecs.getDisplayValue('sys_class_name'); 71 | if (!(clazz in resp)) 72 | resp[clazz] = []; 73 | 74 | var sys_id = taskRecs.getValue('sys_id'); 75 | resp[clazz].push({ 76 | number: taskRecs.getValue('number'), 77 | short_desc: taskRecs.getValue('short_description'), 78 | sys_id: sys_id, 79 | link: gs.getProperty('glide.servlet.uri') + 'api/now/v2/table/' + clazz + '/' + sys_id, 80 | snowui: gs.getProperty('glide.servlet.uri') + clazz + '.do?sys_id=' + sys_id, 81 | created: taskRecs.getValue('sys_created_on') 82 | }); 83 | } 84 | return resp; 85 | }, 86 | type: 'TaskRetriever' 87 | };]]></script><sys_class_name>sys_script_include</sys_class_name><sys_created_by>admin</sys_created_by><sys_created_on>2016-03-13 15:53:00</sys_created_on><sys_customer_update>true</sys_customer_update><sys_id>4b43f5034f4a12002fa02f1e0210c7c5</sys_id><sys_mod_count>1</sys_mod_count><sys_name>TaskRetriever</sys_name><sys_package display_value="My Work" source="x_snc_my_work">11e9a50b4f0a12002fa02f1e0210c737</sys_package><sys_policy>read</sys_policy><sys_replace_on_upgrade>false</sys_replace_on_upgrade><sys_scope display_value="My Work">11e9a50b4f0a12002fa02f1e0210c737</sys_scope><sys_update_name>sys_script_include_4b43f5034f4a12002fa02f1e0210c7c5</sys_update_name><sys_updated_by>admin</sys_updated_by><sys_updated_on>2016-03-14 19:00:42</sys_updated_on></sys_script_include></record_update> 88 | 2f48a7d74f4652002fa02f1e0210c785 89 | false 90 | admin 91 | 2016-03-14 19:01:11 92 | 2348a7d74f4652002fa02f1e0210c786 93 | 0 94 | admin 95 | 2016-03-14 19:01:11 96 | 97 | TaskRetriever 98 | Script Include 99 | global 100 | 101 | 102 | 103 | 104 | INSERT_OR_UPDATE 105 | 11e9a50b4f0a12002fa02f1e0210c737 106 | customer 107 | 108 | sys_ws_version_b7cc25cb4f0a12002fa02f1e0210c7a6 109 | truefalsefalsesys_ws_versionadmin2016-03-13 15:23:08trueb7cc25cb4f0a12002fa02f1e0210c7a62v111e9a50b4f0a12002fa02f1e0210c737false11e9a50b4f0a12002fa02f1e0210c737sys_ws_version_b7cc25cb4f0a12002fa02f1e0210c7a6admin2016-03-14 18:18:471v1fc1aa14b4f0a12002fa02f1e0210c72a]]> 110 | 2f48a7d74f4652002fa02f1e0210c785 111 | false 112 | admin 113 | 2016-03-14 19:01:11 114 | 2748a7d74f4652002fa02f1e0210c786 115 | 0 116 | admin 117 | 2016-03-14 19:01:11 118 |
119 | v1 120 | Scripted REST Version 121 | global 122 | 123 | 124 | 125 | 126 | INSERT_OR_UPDATE 127 | 11e9a50b4f0a12002fa02f1e0210c737 128 | customer 129 | 130 | sys_ws_definition_fc1aa14b4f0a12002fa02f1e0210c72a 131 | true/api/x_snc_my_work/trackerapplication/json,application/xml,text/xmlfalseNo active default versionhttps://morningstoryanddilbert.files.wordpress.com/2014/09/266-strip.giftrueTask tracker APIx_snc_my_workapplication/json,application/xml,text/xmlfalsetrackerUser task trackingsys_ws_definitionadmin2016-03-13 15:14:37truefc1aa14b4f0a12002fa02f1e0210c72a3Task tracker API11e9a50b4f0a12002fa02f1e0210c737false11e9a50b4f0a12002fa02f1e0210c737sys_ws_definition_fc1aa14b4f0a12002fa02f1e0210c72aadmin2016-03-14 18:58:05]]> 132 | 2f48a7d74f4652002fa02f1e0210c785 133 | false 134 | admin 135 | 2016-03-14 19:01:11 136 | 6348a7d74f4652002fa02f1e0210c786 137 | 0 138 | admin 139 | 2016-03-14 19:01:11 140 |
141 | Task tracker API 142 | Scripted REST API 143 | global 144 | 145 | 146 | 147 | 148 | INSERT_OR_UPDATE 149 | 11e9a50b4f0a12002fa02f1e0210c737 150 | customer 151 | 152 | sys_app_11e9a50b4f0a12002fa02f1e0210c737 153 | truetrueMy Workfalsex_snc_my_workx_snc_my_worksys_appadmin2016-03-13 15:10:2411e9a50b4f0a12002fa02f1e0210c7371admin2016-03-14 19:01:04