API-work for kassa.neuf.no

* Starts /api/register.php as primary endpoint for kassa
* Started work on simple card number updates in cardnumber.php
* Reworded sms/register.php
* Update README with markdown syntax
This commit is contained in:
nikolark committed 2015-07-13 23:55:37 +02:00
1 parent 6170baef22
commit 2615f7154d
10 files changed
+310 -110

No files matched your search

+12
View File
@@ -0,0 +1,12 @@
## Konfigurasjon
Du må endre instillinger for database, migrering (key og server), payex betaling og snapporder-integrasjon.
cp inside/credentials-sample.php inside/credentials.php
cp inside/migration/config.example.php inside/migration/config.php
cp includes/payex2/payex_defines.example.php includes/payex2/payex_defines.php
cp snapporder/config-sample.php snapporder/config.php
Du trenger kanskje å endre ting i includes/Ldap_defines.php også.
## Installasjon
Legg inn Apache, MySQL og PHP. Du trenger også noen utvidelser til PHP.
sudo apt-get install php5-mysql php5-ldap
-12
View File
@@ -1,12 +0,0 @@
== Konfigurasjon ==
Du må endre instillinger for database, migrering (key og server), payex betaling og snapporder-integrasjon.
$ cp inside/credentials-sample.php inside/credentials.php
$ cp inside/migration/config.example.php inside/migration/config.php
$ cp includes/payex2/payex_defines.example.php includes/payex2/payex_defines.php
$ cp snapporder/config-sample.php snapporder/config.php
Du trenger kanskje å endre ting i includes/Ldap_defines.php også.
== Installasjon ==
Legg inn Apache, MySQL og PHP. Du trenger også noen utvidelser til PHP.
$ sudo apt-get install php5-mysql php5-ldap
+35 -19
View File
@@ -1,15 +1,26 @@
<?php
set_include_path("../includes/");
set_include_path("../includes/".PATH_SEPARATOR.get_include_path());
require_once("../includes/DB.php");
require_once("../inside/credentials.php");
/* Set HTTP response code */
function set_response_code($code) {
if(!is_int($code)) {
return false;
if( !function_exists('set_response_code') ) {
function set_response_code($code)
{
if (!is_int($code)) {
return false;
}
header('X-Ignore-This: something', true, $code);
}
header('X-Ignore-This: something', true, $code);
}
function return_json_response($data, $response_code=200) {
if($response_code != 200) {
set_response_code($response_code);
}
die(json_encode($data));
}
@@ -40,24 +51,29 @@ function get_db_connection($fetch_mode=NULL, $options=NULL) {
}
function clean_phonenumber($pn) {
$pn = preg_replace('/[^0-9\+]/', '', $pn); // remove everything except valid chars
$pn = preg_replace('/^00/','+', $pn); // replace starting 00 with +
// norwegian phone numbers
if( strlen($pn) === 8 && ($pn[0] === "4" || $pn[0] === "9") ) {
$pn = "+47".$pn;
if( !function_exists('clean_phonenumber') ) {
function clean_phonenumber($pn) {
$pn = preg_replace('/[^0-9\+]/', '', $pn); // remove everything except valid chars
$pn = preg_replace('/^00/', '+', $pn); // replace starting 00 with +
// norwegian phone numbers
if (strlen($pn) === 8 && ($pn[0] === "4" || $pn[0] === "9")) {
$pn = "+47" . $pn;
}
// ...without +
if (strlen($pn) === 10 && $pn[0] === "4" && $pn[1] === "7" && ($pn[2] === "4" || $pn[2] === "9")) {
$pn = "+" . $pn;
}
return $pn;
}
// ...without +
if( strlen($pn) === 10 && $pn[0] === "4" && $pn[1] === "7" && ($pn[2] === "4" || $pn[2] === "9") ) {
$pn = "+".$pn;
}
return $pn;
}
// E.164
function valid_phonenumber($phone) {
return preg_match('/^\+?\d{8,15}$/i', $phone);
if( !function_exists('valid_phonenumber') ) {
// E.164
function valid_phonenumber($phone) {
return preg_match('/^\+?\d{8,15}$/i', $phone);
}
}
+63 -62
View File
@@ -10,79 +10,80 @@ $conn = get_db_connection(DB_FETCHMODE_ORDERED);
if( !isset($_GET['apikey']) ) {
set_response_code(400);
echo json_encode(array('error' => "Missing param apikey."));
die();
return_json_response(array('error' => "Missing param apikey."), 400);
}
/* Valid API KEY (defined in credentials.php) ? */
if( $_GET['apikey'] !== USER_API_KEY && $_GET['apikey'] !== USER_API_KEY_KASSA ) {
set_response_code(400);
echo json_encode(array('error' => "Invalid apikey: '".$_GET['apikey']."'."));
die();
return_json_response(array('error' => "Invalid apikey: '".$_GET['apikey']."'."), 400);
}
if($_SERVER['REQUEST_METHOD'] === 'POST') {
$body = file_get_contents('php://input');
$data = json_decode($body, true);
/* Validate params */
if(!isset($_GET['q'])) {
set_response_code(400);
echo json_encode(array('error' => "Missing param q"));
die();
/* Validate params */
if( !isset($data['card_number']) ) {
return_json_response(array('error' => "Missing param card_number"), 400);
}
$card_number = $data['card_number'];
if( !is_numeric($card_number) ) {
return_json_response(array('error' => "Value card_number must be numeric: '".$card_number."'"), 400);
}
/* Validate user_id */
if( !isset($data['user_id']) ) {
return_json_response(array('error' => "Missing param user_id"), 400);
}
if( !is_numeric($data['user_id']) ) {
return_json_response(array('error' => "Value user_id must be numeric: '".$data['user_id']."'"), 400);
}
/* TODO: If user does not exist, bail */
/* TODO: If user relationship to card exists, bail */
/* TODO: Either Add card relationship OR remove old relationsip and add new */
return_json_response(array('error' => 'TODO: Not implemented'));
}
else {
/* Validate params */
if( !isset($_GET['card_number']) && !isset($_POST['card_number']) ) {
return_json_response(array('error' => "Missing param card_number: ".var_export($_POST, true)), 400);
}
$card_number = $_GET['card_number'];
$card_number = $_GET['q'];
if( !is_numeric($card_number) ) {
return_json_response(array('error' => "Value card_number must be numeric: '".$card_number."'"), 400);
}
if( !is_numeric($card_number) ) {
set_response_code(400);
echo json_encode(array('error' => "Value q must be numeric: '".$card_number."'"));
die();
}
// Search query
$card_number = $conn->quoteSmart($card_number);
$sql = "SELECT mc.userId FROM din_membercard AS mc
LEFT JOIN din_user AS u ON mc.userId=u.id
WHERE mc.id=$card_number";
$card_number = $conn->quoteSmart($card_number);
$res = $conn->getAll($sql);
// Search query
$sql = "
SELECT mc.userId FROM din_membercard AS mc
LEFT JOIN din_user AS u ON mc.userId=u.id
WHERE mc.id=$card_number";
error_reporting(0);
if( DB::isError($res) ) {
return_json_response(array('error' => $res->message), 500);
}
$card_number_exists = count($res) === 0;
$res = $conn->getAll($sql);
/* Invalid card number? */
if($card_number_exists) {
return_json_response(array('user' => NULL, 'valid' => false));
}
if( DB::isError($res) ) {
set_response_code(500);
echo json_encode(array('error' => $res->message));
die();
}
$user_id = $res[0][0];
/* Free card_number? */
if($user_id === "") {
return_json_response(array('user' => NULL, 'valid' => true));
}
/* Invalid card number*/
if(count($res) === 0) {
echo json_encode(array(
'user' => NULL,
'valid' => false
));
die();
}
/* Existing user with card_number. */
try{
$user_data = get_user_data($user_id, $conn);
} catch(Exception $e) {
return_json_response(array('error' => $e->getMessage()), 500);
return; // Note: Help IntelliJ code inspection.
}
$user_id = $res[0][0];
/* Free card_number? */
if($user_id === "") {
echo json_encode(array(
'user' => NULL,
'valid' => true
));
die();
}
/* Existing user with card_number. */
try{
$user_data = get_user_data($user_id, $conn);
} catch(Exception $e) {
set_response_code(500);
echo json_encode(array('error' => $e->getMessage()));
die();
}
echo json_encode(array(
'user' => $user_data,
'valid' => $res !== NULL
));
?>
return_json_response(array('user' => $user_data, 'valid' => $res !== NULL));
}
+184
View File
@@ -0,0 +1,184 @@
<?php
/*
* Registers a user in the user table
*
* Request (new):
*
* $ curl /api/register.php
* {
* "phone": "+4742345678",
* "purchased": "2004-02-12" // optional, format: ISO-8601 date
* "source": "physical" // optional, possible values: "physical", "web" or "manual"
* "membership_trial": "buddy" // optional, gives free membership in autumn, possible value: "buddy"
* }
*
* Response:
*
* {
* "phone": "+4742345678",
* "membership_status": 1, // 0: registrert, 1: medlem, 2: aktivt medlem
* "expires": "2015-04-23",
* "memberid": "4331",
* "firstname": "Jon",
* "lastname": "Hansen",
* "email": "jon@uio.no",
* "birthdate": "1985-03-01",
* "registration_status": "partial" // "partial" means show link
* "membership_trial": "buddy" // possible value: "buddy", user has a trial membership, unset if not
* "registration_url": "/snapporder/register_partial.php?userid=4331&token=lol"
* }
*
* Request (renewal):
*
* $ curl /api/register.php
* {
* "phone": "+4742345678",
* "purchased": "2004-02-12" // optional, format: ISO-8601 date
* "type": "renewal" // optional, possible values: "renewal"
* "source": "physical" // optional, possible values: "physical", "web" or "manual"
* }
*
*/
/* Pull in Inside */
set_include_path("../includes/".PATH_SEPARATOR."../inside/".PATH_SEPARATOR."../snapporder");
require_once("functions.php");
require_once("User.php");
/* Pull in some nifty stuff from snapporder integration */
require_once("api_functions.php");
require_once("lib/functions.php");
require_once("config.php");
/* Validate request */
$body = file_get_contents('php://input');
if(strlen($body) === 0) {
return_json_response(array('error' => 'Invalid request'), 400);
}
/* Decode body */
$data = json_decode($body, true);
if($data === NULL) {
return_json_response(array('error' => 'Can\'t decode body'), 400);
}
/* Check type of registration and set valid fields */
$reg_type = "new";
if( isset($data['type']) && $data['type'] === "renewal" ) {
/* Renewal */
$reg_type = $data['type'];
}
$required_keys = array('apikey', 'phone');
$valid_keys = $required_keys;
$valid_keys = array_merge($valid_keys, array('purchased', 'source', 'type', 'membership_trial', 'cardno'));
$valid_sources = array('physical', 'web', 'manual');
/* Validate supplied data */
foreach($required_keys as $key) {
if(!array_key_exists($key, $data)) {
return_json_response(array('error' => 'missing required field \''.$key.'\''), 400);
}
}
foreach($data as $key => $value) {
if(!in_array($key, $valid_keys)) {
return_json_response(array('error' => 'unknown field \''.$key.'\''), 400);
}
}
/* Valid API KEY (defined in credentials.php) ? */
if( $data['apikey'] !== USER_API_KEY_KASSA ) {
return_json_response(array('error' => "Invalid apikey: '".$data['apikey']."'."), 400);
}
$data['phone'] = clean_phonenumber($data['phone']);
if( !valid_phonenumber($data['phone']) ) {
return_json_response(array('error' => "Not a phone number: '".$data['phone']."'"), 400);
}
$conn = get_db_connection(DB_FETCHMODE_ASSOC);
/* Existing user? */
$user_id = getUseridFromPhone($data['phone']);
if( $reg_type === "new" && $user_id !== false ) {
return_json_response(array('error' => 'Existing user with phone: '.$data['phone']), 409);
}
/* Renewal of membership? */
if( $reg_type === "renewal" && $user_id === false ) {
return_json_response(array('error' => 'Could not find user with phone: '.$data['phone']), 409);
}
$data['user_id'] = $user_id;
if( $reg_type === "renewal") {
$user = get_user($user_id);
/* Don't allow renewal of an existing valid membership. */
if( $user['membership_status'] !== 0 ) {
if($user['expires'] === '') {
// Life long
return_json_response(array('error' => 'Cannot renew, user with phone '.$data['phone'].' has a life long membership.'), 409);
}
return_json_response(array('error' => 'Cannot renew, user with phone '.$data['phone'].' has a valid membership until: '.$user['expires']), 409);
}
}
/* Validate optional purchase_date */
if( isset($data['purchased']) ) {
$purchased = clean_date($data['purchased']) ;
if($purchased === false) {
return_json_response(array('error' => 'Could not parse date from field purchased: '.$data['purchased']), 400);
}
$data['purchased'] = $purchased;
}
/* Validate optional source */
if( isset($data['source']) && !in_array($data['source'], $valid_sources) ) {
return_json_response(array('error' => 'Invalid value in field source: '.$data['source']), 400);
}
/* Validate optional membership_trial */
if( isset($data['membership_trial']) && $data['membership_trial'] !== "buddy") {
return_json_response(array('error' => 'Invalid value in field membership_trial: '.$data['membership_trial']), 400);
}
/* Create user */
try {
if( $reg_type === "new" ) {
$user_id = add_user($data, $data['source']);
} else {
renew_user($data);
}
} catch(InsideDatabaseException $e) {
error_log($e->getMessage());
return_json_response(array('error' => 'db_error', 'error_message' => $e->getMessage()), 500);
}
/* Get and format user */
$user = NULL;
try {
$user = get_user($user_id);
} catch(InsideDatabaseException $e) {
error_log($e->getMessage());
return_json_response(array('error' => 'db_error', 'error_message' => $e->getMessage()), 500);
}
/* Add register url */
if($user['registration_status'] === "partial") {
$user['registration_url'] = generate_registration_url($user, SECRET_KEY);
}
/* Add back phone number from query */
$user['phone'] = $data['phone'];
if( isset($data['membership_trial']) ) {
/* Add back membership_trial from query */
$user['membership_trial'] = $data['membership_trial'];
}
/* Send welcome email */
if($reg_type === "new") {
send_activation_email($data, $user);
// TODO: send_activation_sms($data, $user);
}
/* Return encrypted user object */
return_json_response($user);
+5 -2
View File
@@ -1710,6 +1710,11 @@ function clean_phonenumber($pn) {
if( strlen($pn) === 8 && ($pn[0] === "4" || $pn[0] === "9") ) {
$pn = "+47".$pn;
}
// ...without +
if( strlen($pn) === 10 && $pn[0] === "4" && $pn[1] === "7" && ($pn[2] === "4" || $pn[2] === "9") ) {
$pn = "+".$pn;
}
return $pn;
}
// ISO-8601 Y-m-d
@@ -1788,5 +1793,3 @@ function hash_ldap_password($raw_password) {
return '{SSHA}' . base64_encode(sha1( $raw_password.$salt, TRUE ). $salt);
}
?>
+2 -2
View File
@@ -81,10 +81,10 @@ if( isset($_POST['submit']) ) {
<?php include("../snapporder/header.php"); ?>
<div class="container">
<h1 class="title">Registrering av medlemskap kjøpt på SMS</h1>
<h1 class="title">Registrering av medlemskap kjøpt på SMS eller på Chateau Neuf</h1>
<em class="subtitle">på Det Norske Studentersamfund</em>
<header class="about">
<p>Hei, for at medlemskapet du har kjøpt på SMS skal være gyldig, så <strong>må</strong> du registerere deg.</p>
<p>Hei, for at medlemskapet du har kjøpt på SMS eller på Chateau Neuf skal være gyldig, så <strong>må</strong> du registerere deg.</p>
<p class="imperative">Gå videre med registreringen ved å angi <em>telefonnummer, aktiveringskode, fornavn</em> og <em>epost</em>.</p>
</header>
<section class="register-sms">
+1 -3
View File
@@ -87,6 +87,4 @@ if($user['registration_status'] === "partial") {
/* Return encrypted user object */
echo $crypt->json_encode_and_encrypt($user);
//echo json_encode($user);
?>
//echo json_encode($user);
-2
View File
@@ -236,5 +236,3 @@ if($reg_type === "new") {
/* Return encrypted user object */
echo $crypt->json_encode_and_encrypt($user);
?>
+8 -8
View File
@@ -67,8 +67,9 @@ function add_user($data, $source) {
$user_id = get_user_id_by_username($data['username']);
/* Phonenumber table */
$phone_number_validated = $source === 'snapporder' ? 1 : 0;
$cols = array('user_id', 'number', 'validated');
$values = array($user_id, $phone, 1);
$values = array($user_id, $phone, $phone_number_validated);
$sth = $conn->autoPrepare("din_userphonenumber", $cols, DB_AUTOQUERY_INSERT);
$res = $conn->execute($sth, $values);
@@ -195,11 +196,12 @@ function renew_user($data) {
/* Phonenumber table, set validated */
$fields_values = array('validated' => 1);
if($source === "snapporder") {
$res = $conn->autoExecute("din_userphonenumber", $fields_values, DB_AUTOQUERY_UPDATE, "user_id=$user_id AND number='$phone'");
$res = $conn->autoExecute("din_userphonenumber", $fields_values, DB_AUTOQUERY_UPDATE, "user_id=$user_id AND number='$phone'");
if( DB::isError($res) ) {
throw new InsideDatabaseException($res->getMessage().". DEBUG: ".$res->getDebugInfo());
if( DB::isError($res) ) {
throw new InsideDatabaseException($res->getMessage().". DEBUG: ".$res->getDebugInfo());
}
}
if( isset($data['membership_trial']) && $in_autumn) {
@@ -688,6 +690,4 @@ function send_confirmation_email($data, $user) {
$message .= "</body></html>";
@mail($sendto, $subject, $message, $headers);
}
?>
}