├── 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 | 
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 | 
65 | * To run the project, click the "play" button to build and run the application.
66 |
67 | 
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 | 
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 | 
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 | 
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 | 
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 |
163 | My Work
164 | Custom Application
165 | global
166 |
167 |
168 |
169 |
170 | INSERT_OR_UPDATE
171 | 11e9a50b4f0a12002fa02f1e0210c737
172 | customer
173 |
174 | sys_ws_operation_7bc2bdcf4f0a12002fa02f1e0210c7b3
175 | <?xml version="1.0" encoding="UTF-8"?><record_update table="sys_ws_operation"><sys_ws_operation action="INSERT_OR_UPDATE"><active>true</active><consumes>application/json,application/xml,text/xml</consumes><consumes_customized>false</consumes_customized><default_operation_uri/><enforce_acl/><http_method>GET</http_method><name>My tasks</name><operation_script><![CDATA[/**
176 | Returns collection of task records that are active and assigned to the requesting user
177 | (as identified by gs.getUserID()).
178 | If no matching records are found an empty result object will be returned.
179 | */
180 | (function process(/*RESTAPIRequest*/ request, /*RESTAPIResponse*/ response) {
181 |
182 | // Get current session user id
183 | var userId= gs.getUserID();
184 | var retriever = new x_snc_my_work.TaskRetriever();
185 | // Get records for user and populate response as javascript object
186 | var records = retriever.getTaskRecordsForUser(userId);
187 | var responseObj = retriever.populateResponse(records);
188 | return responseObj;
189 |
190 | })(request, response);]]></operation_script><operation_uri>/api/x_snc_my_work/v1/tracker/task</operation_uri><produces>application/json,application/xml,text/xml</produces><produces_customized>false</produces_customized><relative_path>/task</relative_path><request_example/><requires_acl_authorization>false</requires_acl_authorization><requires_authentication>true</requires_authentication><short_description>Retrieve tasks assigned to the requesting (authenticated) user</short_description><sys_class_name>sys_ws_operation</sys_class_name><sys_created_by>admin</sys_created_by><sys_created_on>2016-03-13 15:49:48</sys_created_on><sys_customer_update>true</sys_customer_update><sys_id>7bc2bdcf4f0a12002fa02f1e0210c7b3</sys_id><sys_mod_count>7</sys_mod_count><sys_name>My tasks</sys_name><sys_package display_value="My Work" source="x_snc_my_work">11e9a50b4f0a12002fa02f1e0210c737</sys_package><sys_policy/><sys_replace_on_upgrade>false</sys_replace_on_upgrade><sys_scope display_value="My Work">11e9a50b4f0a12002fa02f1e0210c737</sys_scope><sys_update_name>sys_ws_operation_7bc2bdcf4f0a12002fa02f1e0210c7b3</sys_update_name><sys_updated_by>admin</sys_updated_by><sys_updated_on>2016-03-14 18:52:12</sys_updated_on><web_service_definition display_value="Task tracker API">fc1aa14b4f0a12002fa02f1e0210c72a</web_service_definition><web_service_version display_value="v1">b7cc25cb4f0a12002fa02f1e0210c7a6</web_service_version></sys_ws_operation></record_update>
191 | 2f48a7d74f4652002fa02f1e0210c785
192 | false
193 | admin
194 | 2016-03-14 19:01:11
195 | a348a7d74f4652002fa02f1e0210c786
196 | 0
197 | admin
198 | 2016-03-14 19:01:11
199 |