Skip to content

API - Basic API calls #24

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 84 commits into
base: gsoc2014
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
9c0bc1b
Added API module
sdaityari May 1, 2014
d1e0c92
API Module- removed unnecessary files, added useful information
sdaityari May 2, 2014
7c2689d
API: Added toro library and created hello world basic handler
sdaityari May 2, 2014
327d861
API: Added structure to the API app
sdaityari May 3, 2014
5142bb4
API: Added functions to demostrate different ways of API calls
sdaityari May 5, 2014
d4a792d
API: Added CORS support
sdaityari May 14, 2014
cf742ac
Merge pull request #23 from sdaityari/toro
sdaityari May 24, 2014
d512f8c
API: Completed basic calls for login and logout
sdaityari May 24, 2014
14e13a9
API: Added check whether token exists to core functions
sdaityari May 25, 2014
3548a5c
API: Moved raise 401 code to basic function
sdaityari May 25, 2014
9b9846e
API: Condensed code
sdaityari May 25, 2014
a16fb46
API: Fixed misc bugs. Changed db structure.
sdaityari May 26, 2014
680c76c
API: Decides access level from member credentials in db
sdaityari May 26, 2014
cd16789
API: Added check for access_level derived from token
sdaityari May 27, 2014
7bcb69d
API: Added course list call with parameters
sdaityari May 29, 2014
8167505
API: Added basic logging capabilities (Only for success cases)
sdaityari May 29, 2014
0a298a3
API: Cleared code
sdaityari Jun 1, 2014
300a46f
API: Added calls for get courses for students and instructors
sdaityari Jun 2, 2014
c4d88eb
API: Separated course logic from core to shared
sdaityari Jun 3, 2014
705c392
API: Added course details for single course for student or instructor
sdaityari Jun 3, 2014
f3b65d4
API: Created functions to re-use SQL for course related calls
sdaityari Jun 4, 2014
3bf92f7
API: Added logging to error messages
sdaityari Jun 4, 2014
0685d5e
API: Added delete call for courses
sdaityari Jun 5, 2014
44da3b5
API: Added get, post and delete calls for course categories
sdaityari Jun 5, 2014
6260d29
API: Modified code
sdaityari Jun 6, 2014
fbebd80
API: Added PUT request to Course Categories, Added SQL clause generat…
sdaityari Jun 9, 2014
a5170ca
API: Added constants for success/error messages
sdaityari Jun 10, 2014
aef08df
API: Removed junk SQL, reusing clause function
sdaityari Jun 11, 2014
0a1cccc
API: Re-factored get_courses_main function to log and output results …
sdaityari Jun 12, 2014
5fe2117
API: Refactored courses get function to generic get function
sdaityari Jun 15, 2014
3a1abd8
API: modified calls to use function api_backbone
sdaityari Jun 15, 2014
bd9eea9
API: Refactored create_SQL_clause
sdaityari Jun 16, 2014
ac68736
API: Refactored api_backbone to accept parameters as an array
sdaityari Jun 16, 2014
55b7dac
API: Fixed bug (instructors, students)
sdaityari Jun 18, 2014
7968cf9
API: Added Join to SQL queries,
sdaityari Jun 19, 2014
8c505af
API: Added boilerplate-example
sdaityari Jun 19, 2014
791e17b
API: Added queries_after option to backbone, refactored course catego…
sdaityari Jun 20, 2014
1ef7899
API: Added PUT, POST for courses
sdaityari Jun 20, 2014
7b1e6e1
API: Added calls for member lists and details (students, instructors)
sdaityari Jun 21, 2014
b6601c9
API: Modified GET calls for member lists
sdaityari Jun 24, 2014
9ab9556
API: Changed check_access_level function to return count of rows
sdaityari Jun 24, 2014
65b0d82
API: Added member list calls for courses (enrolled students, instruct…
sdaityari Jun 25, 2014
9c77f84
API: Added user_agent to logs, Option for admin to download logs
sdaityari Jun 26, 2014
2956a59
API: Download log for admin forces file download
sdaityari Jun 27, 2014
06684c8
API: Set three logging levels for logging of API requests
sdaityari Jun 27, 2014
df9c0ad
API: Added token expiry to settings
sdaityari Jun 27, 2014
604f1a2
API: Added admin settings for logging level and token expiry, Added o…
sdaityari Jun 27, 2014
6159144
API: Added instructor calls for PUT, POST, DELETE,
sdaityari Jul 1, 2014
a41c372
API: Added option for admin to clear inactive API tokens
sdaityari Jul 1, 2014
102e527
API: Removed queries_after code from api_backbone
sdaityari Jul 1, 2014
697b7b0
API: Fixed bug in error printing
sdaityari Jul 1, 2014
50a5947
API: Added student PUT, POST and DELETE calls
sdaityari Jul 2, 2014
069bd09
API(Alternate branch): Added first few calls without using get_course…
sdaityari Jul 4, 2014
ab93eb9
API Alternate: Added alternate instructor functions without using get…
sdaityari Jul 5, 2014
11686cb
API Alternate: Added alternate student functions without using get_co…
sdaityari Jul 5, 2014
dec7a49
API: Give member_id and access_level on successful login
sdaityari Jul 7, 2014
b6c7dbe
API: Merge branch 'api_alternate' into api
sdaityari Jul 8, 2014
74481a6
API: Removed the usage of get_members_main
sdaityari Jul 8, 2014
03f080c
API: Removed usage of get_enrolled_members function
sdaityari Jul 8, 2014
7f51065
API: Removed unused functions
sdaityari Jul 9, 2014
20f5d5d
API: Removed commented out calls to unused functions
sdaityari Jul 9, 2014
6944421
API: Created more detailed boilerplate examples
sdaityari Jul 9, 2014
942797b
API: Modified boilerplate as per comments
sdaityari Jul 9, 2014
b2d530e
API: Modified SQL clause function
sdaityari Jul 10, 2014
68085d4
API Merge: Merged get functions with and without id for courses
sdaityari Jul 10, 2014
9ff0e2a
API Merge: Merged classes for instructors and students
sdaityari Jul 11, 2014
78dc07f
API Merge - Cleaned code acc to comments
sdaityari Jul 14, 2014
0df3280
API: Added tests app
sdaityari Jul 15, 2014
c86c89f
API: Added missing tests directory
sdaityari Jul 15, 2014
8009936
API: Added questions app
sdaityari Jul 17, 2014
dcdf6be
API: Added question categories API calls
sdaityari Jul 17, 2014
00e1bef
API: Added question calls for tests, instructors and students
sdaityari Jul 18, 2014
2c36ac7
API: Removed 500 error on local machine (PHP version issue)
sdaityari Jul 23, 2014
39481db
API: Made first set of SQL modifications
sdaityari Jul 23, 2014
9965262
API: Added http_response_code function support for old php versions
sdaityari Jul 24, 2014
84c15d9
API: Modified SQL for Courses (changed INNER JOIN to LEFT OUTER JOIN …
sdaityari Jul 24, 2014
3b746f0
API: Added SQL structure to remaining files (instructors, studetnts, …
sdaityari Jul 25, 2014
303d805
API: Added PUT, POST and DELETE calls for tests
sdaityari Jul 26, 2014
2ecaa98
API: Added question and test map calls
sdaityari Jul 29, 2014
cd866d1
API: Added POST, PUT and DELETE calls for quesions, without consideri…
sdaityari Jul 31, 2014
7d5e254
API: Added call to add question deatails
sdaityari Aug 1, 2014
cf51fb5
API: Fixed error with SQL query to check question existence in detail…
sdaityari Aug 1, 2014
2397990
API: Added more question calls for instructors and students for details
sdaityari Aug 4, 2014
4a7ee20
API: Added UI to admin page
sdaityari Aug 6, 2014
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions api/.htaccess
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
RewriteEngine On
RewriteCond %{ENV:REDIRECT_STATUS} ^$
#RewriteCond %{REQUEST_FILENAME} !-f
#RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L]
105 changes: 105 additions & 0 deletions api/boilerplate-example/router_classes.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
<?php
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is an example when a custom field is returned back (e.g. after POST you return ID of the freshly created entity) ?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is an example where you show how extra logic is being execute right after api_backbone() function?


Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not see sql_clause() function anywhere. It is VERY important function when you pass query parameters but not sure if all of them are present. Where is explanation for that?

class BoilerplateClass {
function get() {
// Make a call to the API function like this
// Specify a request type, access level and query to be executed.

// You may want to add certain WHERE parameters to your query (which may or may not be present)
// An associative array is an argument - the keys are the names of the db columns as they appear in the query
// - the values are the variables that may or may not exist in the call
// Uncomment the following call to generate the clause according to the variables that are present

// create_SQL_clause(array(
// "title" => $_GET["title"],
// "language" => $_GET["language"]
// ));

// Uncomment the following for a sample call (make sure you set the variables first)

/* api_backbone(array(
* "request_type" => HTTP_GET,
* "access_level" => INSTRUCTOR_ACCESS_LEVEL,
* "query" => $query,
* "query_array" => $array
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still believe that you need to pass "referece_id". If the value is passed then it is compare against member_id which is associated with the token which is passed in request

* ));
*/
print "You are at the boilerplate home!";
}

function post() {
// Make a call to the API function like this
// Specify a request type, access level and query to be executed.
// We create an object and return the ID with this call.
// To get the ID of the newly created object, set returned_id_name to true

// Uncomment the following for a sample call (make sure you set the variables first)
/* api_backbone(array(
* "request_type" => HTTP_POST,
* "access_level" => INSTRUCTOR_ACCESS_LEVEL,
* "query" => $query,
* "query_array" => $array,
* "returned_id_name" => true
* ));
*/
print "You are at the boilerplate home! Creating an object.";
}
}

class BoilerplateClassWithUrlParameter{
function get($boilerplate_id) {
// Make a call to the API function like this
// Since we want a single object, we specify one_row to be true
/* api_backbone(array(
* "request_type" => HTTP_GET,
* "access_level" => ADMIN_ACCESS_LEVEL,
* "query" => $query,
* "query_array" => $array,
* "one_row" => true
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is this option : "one_row" what is it for ?

* ));
*/
print "Checking boilerplace with id - ".$boilerplate_id;
}

function put($boilerplate_id) {
// Make a call to the API function like this
// We update an object here, so we need to check if it exists first, which is accomplished by query_id_existence
// No need to specify one_row because we perform an update operation here
// Uncomment the following for a sample call (make sure you set the variables first)
/* api_backbone(array(
* "request_type" => HTTP_PUT,
* "access_level" => ADMIN_ACCESS_LEVEL,
* "query_id_existence" => $query_id_existence,
* "query_id_existence_array" => $query_id_existence_array,
* "query" => $query,
* "query_array" => $array
* ));
*/
print "Updating boilerplace object with id - ".$boilerplate_id;
}

function delete($boilerplate_id) {
// Make a call to the API function like this
// We delete an object here, so we need to check if it exists first, which is accomplished by query_id_existence
// Uncomment the following for a sample call (make sure you set the variables first)
/* api_backbone(array(
* "request_type" => HTTP_DELETE,
* "access_level" => ADMIN_ACCESS_LEVEL,
* "query_id_existence" => $query_id_existence,
* "query_id_existence_array" => $query_id_existence_array,
* "query" => $query,
* "query_array" => $array
* ));
*/

// There are chances where you might want to execute something after the API call
// For example, after you delete a course, you want to clear the enrollment tables
// For this you need to manually use queryDB after you complete the call to api_backbone

// queryDB($second_query, $second_query_array);

print "Deleting boilerplace with id - ".$boilerplate_id;
}
}

?>
17 changes: 17 additions & 0 deletions api/boilerplate-example/urls.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

if (!defined('AT_INCLUDE_PATH')) {
exit;
}

// The prefix common to all URLs in this boilerplate example app
$boilerplate_url_prefix = "/boilerplate";

$boilerplate_base_urls = array(
"/" => "BoilerplateClass",
"/:number" => "BoilerplateClassWithUrlParameter"
);

$boilerplate_urls = generate_urls($boilerplate_base_urls, $boilerplate_url_prefix);

?>
234 changes: 234 additions & 0 deletions api/core/api_functions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
<?php

if (!defined('AT_INCLUDE_PATH')) {
exit;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do you use exit instead of return ?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So that if someone opens that in a browser, it doesn't open. I have noticed the same block of code in many other ATutor files.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

}

/*
* Support for PHP < 5.4
* More info - http://stackoverflow.com/questions/3258634/php-how-to-send-http-response-code
*/

if (!function_exists('http_response_code'))
{
function http_response_code($newcode = NULL)
{
static $code = 200;
if($newcode != NULL)
{
header('X-PHP-Response-Code: '.$newcode, true, $newcode);
if(!headers_sent())
$code = $newcode;
}
return $code;
}
}

function api_module_status() {
// To check if the module is activated/activated
$enabled = queryDB("SELECT
*
FROM
%smodules
WHERE
dir_name = '%s'
AND
status = %d",
array(TABLE_PREFIX,
"_standard/api",
2));

return count($enabled)?true:false;
}

function generate_urls($old_array, $prefix) {
// Add prefix to all indices of old array
$new_array = array();
foreach($old_array as $key => $value) {
$new_array[$prefix.$key] = $value;
}
return $new_array;
}

function check_token($token, $minimum_access_level){
$check = queryDB("SELECT
access_level
, member_id
FROM
%sapi
WHERE
token = '%s'
AND
expiry > CURRENT_TIMESTAMP",
array(TABLE_PREFIX,
$token), true);

if (!$check) {
http_response_code(401);
print_message(ERROR, TOKEN_DOES_NOT_EXIST);
exit;
} else if ($check["access_level"] > $minimum_access_level) {
http_response_code(401);
print_message(ERROR, YOU_ARE_NOT_AUTHORIZED_TO_ACCESS_THIS_RESOURCE);
exit;
}

$query = "UPDATE
%sapi
SET
modified = CURRENT_TIMESTAMP
, expiry = NOW() + INTERVAL %d DAY
WHERE
token = '%s'";

$query_array = array(TABLE_PREFIX,
TOKEN_EXPIRY,
$token);

if (DEBUG) {
print vsprintf($query, $query_array);
print "\n\n";
}

// Update modified timestamp
queryDB($query, $query_array);

return $check["member_id"];
}

function check_access_level($token, $access_level = ADMIN_ACCESS_LEVEL) {
$check = queryDB("SELECT
COUNT(*)
FROM
%sapi
WHERE
token = '%s'
AND
access_level <= %d",
array(TABLE_PREFIX,
$token,
$access_level), true);

return $check > 0 ? true : false;
}

function get_access_token($headers, $minimum_access_level = ADMIN_ACCESS_LEVEL,
$return_member_id = false) {

/**
* $headers - assoc array of headers
* $minimum_access_level - the user with the lowest permissions that can access this
* $return_member_id - whether to return a tuple or token and member_id
*/

$token = addslashes($headers[TOKEN_NAME]);
$member_id = check_token($token, $minimum_access_level);

if ($member_id && $return_member_id){
return array($token, $member_id);
} else if ($member_id) {
return $token;
} else {
return false;
}
}

function print_message($type, $message, $log = array(), $http_method = HTTP_GET) {
if (!$log) {
$log = generate_basic_log($_SERVER);
$headers = getallheaders();
$log["token"] = $headers[TOKEN_NAME];
}
$key = $type == ERROR ? "errorMessage" : "successMessage";
$response = json_encode(array(
$key => $message
));
$log["response"] = $response;
log_request($log, $http_method, $type == ERROR);
echo $response;
exit;
}

function generate_basic_log($request) {
$log = array();
$log["ip_address"] = $request["REMOTE_ADDR"];
$log["request_uri"] = $request["REQUEST_URI"];
$log["http_method"] = $request["REQUEST_METHOD"];
$log["user_agent"] = $request["HTTP_USER_AGENT"];
return $log;
}

function log_request($log = array(), $http_method = HTTP_GET, $error = false) {
if ((LOGGING_LEVEL == NO_LOGGING) ||
($http_method == HTTP_GET && LOGGING_LEVEL == LOGGING_EXCEPT_GET && !$error)) {
return;
}

$query = "INSERT INTO %sapi_logs(
ip_address
, user_agent
, request_uri
, http_method
, token
, response)
VALUES(
'%s'
, '%s'
, '%s'
, '%s'
, '%s'
, '%s')";

$query_array = array(TABLE_PREFIX,
$log["ip_address"],
$log["user_agent"],
$log["request_uri"],
$log["http_method"],
$log["token"],
$log["response"]
);

if (DEBUG) {
print vsprintf($query, $query_array);
print "\n\n";
}

queryDB($query, $query_array);


}

function return_created_id($id, $log) {
$response = json_encode(array(
"successMessage" => ACTION_COMPLETED_SUCCESSFULLY,
"id" => $id
));
echo $response;
}

function create_SQL_clause($terms, $prefix = "WHERE", $sanitize = true) {
/*
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function should run addslashes on every passed argument. Also you need to make this configurable just like queryDB (by default the function applies to every argument but use can say that no need to apply it)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function should not look into requests object. You need to pass array of "name" => value type of thing. There will be moments when some arguments come from URL, some from URL query and some from body. So just make function more dumb enough to work with simple name, value pairs

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function should be smart enough to add WHERE clause is needed. (I guess add an extra argument. By default it is false but if it is specified as true then the string will start with WHERE ... )

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure addslashes is not run within queryDB? Because this cause will run through queryDB later.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this function you assemble a full string where you put values as well. Since you put values in then you might want to run addslashes for every value.

* Function to create SQL clause
* $terms is an associative array
* The keys of $terms represent the column names as they appear in the SQL
* For example, create_SQL_clause(array(
* "title" => "My Course",
* "language" => "en")) should return
* "WHERE c.title = 'My Course' AND c.language = 'en'"
*/
$query = "";
$prefix = $prefix ? $prefix . " " : "";
foreach ($terms as $key => $value) {
if ($value) {
if ($query != "")
$query = $query."AND ";
$query = $sanitize ? $query.$key." = '". addslashes($value) ."' " : $query.$key." = '". $value ."' ";
}
}
if ($query != ""){
$query = $prefix . $query;
}
return $query;
}

?>
Loading