Sistem Presensi Kuliah dengan Twitter (Twitter sebagai SMS Gateway)
10 February 2011 at 11:13 | Posted in Uncategorized | 3 CommentsSemester ini saya mulai menerapkan aturan kehadiran sebagai syarat ujian. Sistem yang ada saat ini adalah berbasis tandatangan, dan saya malas merekapnya menjelang ujian (malas itu adalah ibu-nya dari penemuan hehe). Setelah mempertimbangkan beberapa hal, akhirnya saya menjadikan Twitter sebagai media. Skenarionya adalah sbb:
- Mahasiswa mendaftarkan account, nim dan nama, dengan mengirimkan tweet dengan me-mention account khusus yang telah disiapkan. Misalnya @sayahadir reg 04001 Budi Martami
- Mahasiswa mendaftarkan matakuliah, misalnya: @sayahadir regmk IK331
- Saat kuliah, mahasiswa presensi dengan tweet: @sayahadir hdr
Semua proses diatas semua dilakukan oleh mahasiswa secara mandiri sehingga memudahkan saya. Reply dikirim untuk setiap transaksi. Dari sisi authorisasi, tentu saja sistem ini sama lemahnya sistem manual yang dapat menitipkan tandatangan. Mahasiswa dapat mengirimkan tweet dari tempat tidur saat jam kuliah atau bahkan membuat script yang mengirimkan tweet otomatis. Memang bukan itu tujuannya. Pencegahannya dengan cara biasa, dipanggil satu-satu atau secara acak, dihitung dan diberi sanksi nilai E kalau curang.
Twitter dipilih karena memiliki fasilitas pengiriman SMS untuk semua operator: Indosat, Telkomsel, XL, Three, Axis, Flexi dan Esia. Mahasiswa hanya cukup menggunakan HP yang memiliki fasilitas SMS (tidak perlu internet apalagi GPS). Lagipula saya memang sedang tertarik dengan layanan Twitter ini (dalam rangka tweetmining)
Saat weekend saya mulai implementasi ide ini (jadi harap maklum kalau code-nya masih berantakan, dikerjakan disela-sela waktu hehe). Implementasinya sederhana. Ada tiga modul. Modul pertama untuk ’mendengarkan’ mention tweet dari mahasiswa yang berisi request pendaftaran (reg, regmk) dan kehadiran (hdr), mention ini kemudian disimpan ke dalam database. Modul kedua adalah melakukan pemrosesan (pendaftaran, kehadiran) dan menyimpan responnya di tabel. Modul ketiga adalah membaca respon tersebut dan menjadikannya reply agar dapat dibaca mahasiswa.
Diperlukan satu account twitter yang digunakan untuk menerima permintaan dan memberikan reply. Account ini dapat dianggap sebagai gerbang input-output komunikasi antar user dengan sistem. Karena twitter dapat dijalankan dengan SMS, dapat dianggap twitter ini sebagai SMS gateway. Jadi sebenarnya aplikasi presensi dapat digunakan untuk aplikasi-aplikasi lain.
Pertama kita siapkan account untuk ‘dikendalikan’ (saya pilih account @syhdr yang merupakan singkatan dari sayahadir). Kemudian kita harus mendaftarkan aplikasi yang dapat membaca atau menulis account tersebut. Daftarkan aplikasi ini lewat https://twitter.com/apps untuk mendapatkan CONSUMER_KEY dan CONSUMER_SECRET.
Untuk berkomunikasi dengan Twitter, saya gunakan library twitteroauth. Download dan baca file DOCUMENTATION, index.php dan test.php. Upload dan jalankan index.php atau test.php untuk melihat bagaimana library ini bekerja. Langkah berikutnya adalalah menghubungkan antara aplikasi twitter dengan account @syhdr. Tambahkan dua baris dibawah $access_token = $_SESSION['access_token']; pada file index.php
$access_token = $_SESSION['access_token']; echo token=$access_token['oauth_token']; echo token_secret=$access_token['oauth_token_secret'];
Token dan token secret adalah dua variabel yang dibutuhkan bagi sebuah aplikasi Twitter untuk dapat mengakses sebuah account Twitter. Jalankan program dan berikan ijin read/write untuk account @syhdr. Catat dua variabel ini.
Setelah mendapatkan consumer_key, consumer_secret, token, dan token_secret sekarang kita dapat memulai. Semua variabel tersebut saya simpan dalam file conf.php:
<?php
define('CONSUMER_KEY', 'b5Hj------');
define('CONSUMER_SECRET', 'JiMaG----');
define('TOKEN','24635---');
define('TOKEN_SECRET','cJ591N---');
define('USER','----');
define('PASSWORD','---');
define('DATABASE','---');
?>
Modul pertama adalah membaca mention. Tweet yang berisi mention @syhdr akan dimasukkan untuk dproses lebih lanjut. Setiap tweet memiliki ID yang unik, ini perlu disimpan agar tidak ada dua tweet yang sama yang masuk ke database. Kemudian tanggal tweet juga berbeda dengan tanggal standard, sehingga perlu dikonversi dulu.
<?php
//baca mentions dari account twiiter
require_once('twitteroauth/twitteroauth.php');
require_once('conf.php');
function parseTwitterDate ($twDate) {
//parse twitter date ke date dan zone indonesia GMT+7 (string)
//contoh input: Fri Feb 04 10:12:27 +0000 2011
//contoh ouput: '2011-02-04 17:12:27'
$p = explode(" ",$twDate); //0: hari, 1: bulan, 2: tgl, 3:jam, 4 skip, 5: tahun
$strDate = "{$p[5]}-{$p[1]}-{$p[2]} {$p[3]}";
$phpDate = strtotime($strDate)+(3600*7); //tambah 7 jam
$mysqlDate = date('Y-m-d H:i:s',$phpDate);
return $mysqlDate;
}
$connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, TOKEN, TOKEN_SECRET);
$response = $connection->get('statuses/mentions');
mysql_connect(localhost,USER,PASSWORD) or die ("Tidak dapat connect ke db");
mysql_select_db(DATABASE) or die( "Tidak dapat select database");
foreach ($response as $mention) {
$user = $mention->user;
//insert ke database, cek berdasarkan id_str, kalau sudah ada, jangan dimasukkan
$query = "SELECT count(*) FROM MENTION WHERE id_tweet = {$mention->id_str} LIMIT 1";
$result=mysql_query($query);
$tempRow = mysql_fetch_row($result);
$num_rows = $tempRow[0];
if ($num_rows==0) { //belum ada
//insert mention ke database
$tweetDate = parseTwitterDate($mention->created_at);
$qInsert = "INSERT INTO MENTION(ID_TWEET, TEXT, TIME, ID_USER_TWITTER, SCREEN_NAME) VALUES ({$mention->id_str},'{$mention->text}','$tweetDate',{$user->id_str},'{$user->screen_name}')";
echo $qInsert;
$result = mysql_query($qInsert);
if (!$result) {
die('Invalid query: ' . mysql_error());
}
}
}
mysql_close();
?>
Modul kedua adalah memproses mention dari mahasiswa. Contoh mention seperti “@syhdr reg 04001 Budi”. Kata kedua berisi perintah. “REG” berarti pendaftaran mahasiswa (diproses oleh fungsi regMhs), “REGMK” berarti pendaftaran matakuliah (fungsi regMatakuliah) dan “HDR” berarti presensi dan diproses pada fungsi hadir. Respon dari setiap request kemudian disimpan di database.
<?php
//syntax mention
//1. @syhdr reg NIM NAMA --> daftar nim dan nama
// contoh: @syhdr reg 04002 encep fanda
//2. @syhdr regmk KODEMK
// contoh: @syhdr regmk IK331
//3. @syhdr hdr
//cek apa ada data yg perlu diproses, jika tidak, skip
require_once('conf.php');
mysql_connect(localhost,USER,PASSWORD) or die ("Tidak dapat connect ke db");
mysql_select_db(DATABASE) or die( "Tidak dapat select database");
$query = "select count(*) as JUM from MENTION where IS_PROSES=0 and SCREEN_NAME<>'syhdr'";
$res=mysql_query($query);
if (!$res) { die ("query error: $query");}
$tempRow = mysql_fetch_row($res);
$num_rows = $tempRow[0];
if ($num_rows==0) {
echo 'tdk ada yg diproses, keluar';
exit();
}
function flagIsProsesMention($idMention) {
//tandai bahwa record sudah diproses di tabel mention
$query = "update MENTION set IS_PROSES=1 where ID_MENTION=$idMention";
$result=mysql_query($query);
if (!$result) { die ("query error: $query");}
}
function setReply($id_tweet,$id_user_twitter,$screen_name,$msg) {
//reply ke user, baik kalau perintah berhasil maupun salah
$query = "insert into REPLY(ID_TWEET,ID_USER_TWITTER,SCREEN_NAME,TEXT) VALUES ($id_tweet,$id_user_twitter,'$screen_name','$msg')";
$result=mysql_query($query);
if (!$result) { die ("query error: $query"); }
}
function hadir($row) {
//contoh: @syhdr hdr
//cek apakah mhs sudah terdaftar di matakuliah dan matakuliah sesuai jadwal
$query = "select mhs.ID_MHS, j.ID_JADWAL
from
JADWAL j,
MHS_MATAKULIAH mm,
MHS mhs,
MATAKULIAH mk
where
j.ID_MK = mk.ID_MK and
mm.ID_MK = mk.ID_MK and
mhs.ID_MHS = mm.ID_MHS and
mhs.ID_USER_TWITTER = {$row['ID_USER_TWITTER']} and
WEEKDAY('{$row['TIME']}') = j.WDAY and
TIME('{$row['TIME']}') >= j.START_TIME and
TIME('{$row['TIME']}') <= j.END_TIME
";
$result=mysql_query($query);
if (!$result) { die ("query error: $query");}
$tempRow = mysql_fetch_assoc($result);
if (!$tempRow) {
//ada 3 kemungkinan
echo "mhs tdk terdaftar atu blm mendaftar mk atau jadwal belummulai/sudahselesai";
setReply($row['ID_TWEET'],$row['ID_USER_TWITTER'],$row['SCREEN_NAME'],"gagal!mhs tdk terdaftr atau mk tdk terdaftr atau jdwl tdk ada;");
} else { //mhs terdaftar, mhs sudah reg matakuliah, jadwal ada yg cocok
//periksa apakah sudah ada di kehadiran?
$id_jadwal = $tempRow['ID_JADWAL'];
$id_mhs = $tempRow['ID_MHS'];
$query = "select count(*) from KEHADIRAN where ID_JADWAL = $id_jadwal and ID_MHS = $id_mhs";
$result=mysql_query($query);
if (!$result) { die ("query error: $query");}
$tempRow = mysql_fetch_row($result);
$num_rows = $tempRow[0];
if ($num_rows==0) { //tidak ada, insert
$query = "insert into KEHADIRAN(ID_JADWAL,ID_MHS,TIMESTAMP) values ($id_jadwal,$id_mhs,'{$row['TIME']}')";
echo $query;
$result=mysql_query($query);
if (!$result) { die ("query error: $query");}
setReply($row['ID_TWEET'],$row['ID_USER_TWITTER'],$row['SCREEN_NAME']," hadir!;");
} else
{
//batal, karena sudah
echo "{$row['SCREEN_NAME']} sudah memberikan presensi";
//tidak perlu direply karena percuma juga, dan mungkin banyak, lebih baik duplikasi diignore saja
}
}
flagIsProsesMention($row['ID_MENTION']);
}
function regMatakuliah($p,$row) {
//contoh @syhdr regmk IK331
//cek apakah sudah pernah mendaftar kuliah tsb
$kodeMk = mysql_real_escape_string($p[2]);
$query = "select count(*) from MHS_MATAKULIAH mm, MATAKULIAH mk, MHS where mm.ID_MHS=MHS.ID_MHS and mm.ID_MK = mk.ID_MK and mk.KODE_MK = '$kodeMk' and MHS.ID_USER_TWITTER = {$row['ID_USER_TWITTER']}";
$result=mysql_query($query);
if (!$result) { die ("query error: $query");}
$tempRow = mysql_fetch_row($result);
$num_rows = $tempRow[0];
if ($num_rows==0) { //tidak ada di tabel MHS_MATAKULIAH, add
//cari ID matakuliah
$query = "select ID_MK from MATAKULIAH where KODE_MK='$kodeMk'";
$result=mysql_query($query);
if (!$result) { die ("query error: $query");}
$tempRow = mysql_fetch_row($result);
if (!$tempRow) { //matakuliah tdk terdaftar error
echo "matakuliah $kodeMk tidak terdaftar";
setReply($row['ID_TWEET'],$row['ID_USER_TWITTER'],$row['SCREEN_NAME'],"gagal! tdk ada mk $kodeMk;");
} else
{
$id_mk = $tempRow[0];
//cek apakah mahasiswa sudah terdaftar
$query = "select ID_MHS from MHS where ID_USER_TWITTER={$row['ID_USER_TWITTER']}";
$result=mysql_query($query);
if (!$result) { die ("query error: $query");}
$tempRow = mysql_fetch_row($result);
if (!$tempRow) { //mhs tdk terdaftar error
echo "mhs, {$row['SCREEN_NAME']} tidak terdaftar";
setReply($row['ID_TWEET'],$row['ID_USER_TWITTER'],$row['SCREEN_NAME'],"mhs atau twitter account belum terdaftar!;");
} else {
$id_mhs = $tempRow[0];
$query = "insert into MHS_MATAKULIAH(ID_MHS,ID_MK,TGL_DAFTAR) values ($id_mhs,$id_mk,'{$row['TIME']}')";
$result=mysql_query($query);
if (!$result) { die ("query error: $query");}
setReply($row['ID_TWEET'],$row['ID_USER_TWITTER'],$row['SCREEN_NAME'],"berhasil mendaftar ke $kodeMk;");
}
}
} else
{
//tdk dimasukkan, sudah terdaftar
echo "matakuliah dan nim tsb sudah terdaftar";
setReply($row['ID_TWEET'],$row['ID_USER_TWITTER'],$row['SCREEN_NAME'],"$kodeMk sudah terdaftar!");
}
// tandai di tabel mention bahwa sudah diproses
flagIsProsesMention($row['ID_MENTION']);
}
function regMhs($p,$row) {
//contoh @syhdr reg NIM NAMA
if ($p[2]!=null && $p[3]!=null) {
//format sudah valid, bisa proses
//p[2] = NIM p[3] dst = NAMA
//cek apakah idtwitter atau NIM di tabel mhs sudah ada?
$nim = mysql_real_escape_string($p[2]);
$query = "select count(*) from MHS where ID_USER_TWITTER={$row['ID_USER_TWITTER']} OR NIM='$nim'";
$result=mysql_query($query);
if (!$result) { die ("query error: $query");}
$tempRow = mysql_fetch_row($result);
$num_rows = $tempRow[0];
if ($num_rows==0) { //belum ada di tabel mhs, add
//ambil nama lengkap
for ($i=3;$i<sizeof($p);$i++) {
$nama = $nama .' '. $p[$i];
}
$nama=mysql_real_escape_string($nama);
//insert ke tabel mhs
$query = "insert into MHS(NIM,NAMA,SCREEN_NAME,ID_USER_TWITTER) values ('$nim','$nama','{$row['SCREEN_NAME']}',{$row['ID_USER_TWITTER']})";
$result=mysql_query($query);
if (!$result) { die ("query error: $query");}
echo $query."<br>";
//add
setReply($row['ID_TWEET'],$row['ID_USER_TWITTER'],$row['SCREEN_NAME'],"$nim sukses terdaftar;");
} else {
//duplikasi id_twitter atau NIM
echo "{$row['SCREEN_NAME']} atau NIM=$p[2] sudah terdaftar";
setReply($row['ID_TWEET'],$row['ID_USER_TWITTER'],$row['SCREEN_NAME']," {$row['SCREEN_NAME']} atau NIM=$p[2] sudah terdaftar;");
}
} else
{
//reply format salah
echo "format yang benar mendaftarkan diri adalah: @syhdr reg NIM NAMA";
setReply($row['ID_TWEET'],$row['ID_USER_TWITTER'],$row['SCREEN_NAME'],"gagal!format yg bnr adl:@syhdr reg NIM NAMA;");
}
// tandai di tabel mention bahwa sudah diproses
flagIsProsesMention($row['ID_MENTION']);
}
//cek apakah ada data mention yg harus diproses
$query = "select ID_MENTION,ID_TWEET,TEXT,TIME,ID_USER_TWITTER,SCREEN_NAME from MENTION where IS_PROSES=0 and SCREEN_NAME<>'syhdr' ORDER BY ID_TWEET";
$result=mysql_query($query);
if (!$result) { die ("query error: $query");}
while ($row = mysql_fetch_assoc($result)) {
$text = trim(strtoupper($row['TEXT']));
echo $text."<br>";
$p = preg_split("/[ ]+/",$text); //explode gagal kalau ada lebih dari satu spasi
if ($p[0] =! '@SYHDR') {
//format error, kirim reply agar user menggunakan format yang benar
setReply($row['ID_TWEET'],$row['ID_USER_TWITTER'],$row['SCREEN_NAME'],"perintah tdk dikenal!hrs diawali @syhdr");
flagIsProsesMention($row['ID_MENTION']);
} else {
if ($p[1] == 'REG') {
//pendaftaran mhs
echo "<br>reg mhs<br>";
regMhs($p,$row);
} elseif ($p[1] == 'REGMK') {
//pendaftaran matakuliah
echo "<br>reg matakuliah<br>";
regMatakuliah($p,$row);
} elseif ($p[1] == 'HDR') {
//presensei
echo "<br>Hadir<br>";
hadir($row);
} else
{
//error: kata kedua bukan reg,regmk, hdr
echo "<br>perintah tidak dikenal!<br>";
setReply($row['ID_TWEET'],$row['ID_USER_TWITTER'],$row['SCREEN_NAME'],"perintah tdk dikenal!kata kedua hrs regmk,reg,hdr;");
flagIsProsesMention($row['ID_MENTION']);
}
}
}
?>
Modul ketiga, membaca reply dari database dan mengirimkannya. Untuk menghemat (karena Twitter API membatasi jumlah komunikasi antara aplikasi dengan Twitter), maka beberapa reply dapat digabung dalam satu tweet.
<?php
//baca mentions dari account twiiter
require_once('twitteroauth/twitteroauth.php');
require_once('conf.php');
mysql_connect(localhost,USER,PASSWORD) or die ("Tidak dapat connect ke db");
mysql_select_db(DATABASE) or die( "Tidak dapat select database");
$stop = false;
$msg = "";
$sentID_Reply ="(";
$query = "select ID_REPLY,ID_TWEET,TEXT,ID_USER_TWITTER,SCREEN_NAME from REPLY where IS_SENT=0 ORDER BY ID_TWEET";
$result=mysql_query($query);
if (!$result) { die ("query error: $query");}
while (($row = mysql_fetch_assoc($result)) && !($stop)) {
//ada reply harus dikirim
$oldMsg = $msg;
$msg = $msg. '@'.$row['SCREEN_NAME']. " ".$row['TEXT']." ";
if (strlen($msg) > 140 ) { //kelebihan, batal yg terakhir
$msg = $oldMsg;
$stop = true;
} else { //cukup
$sentID_Reply = $sentID_Reply. $row['ID_REPLY'].",";
}
}
if ($msg!="") { //ada yg perlu dikirim
echo "<br> $msg <br>";
$connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, TOKEN, TOKEN_SECRET);
$connection->post('statuses/update', array('status' => $msg));
$sentID_Reply = $sentID_Reply. "-9999999)"; //dummy
//update IS_SENT ke 1, artinya sudah diproses
$query = "update REPLY set IS_SENT=1 where ID_REPLY IN ".$sentID_Reply;
echo $query;
$result=mysql_query($query);
if (!$result) { die ("query error: $query");}
} else {
echo "tidak ada yg perlu dikirim";
}
?>
Terakhir, gunakan cron untuk memanggil ketiga modul ini (readMention, prosesMention dan sendReply) dalam periode tertentu. Ketiga modul ini dapat dijalankan secara async, tidak harus berurutan.
-update: sistem ini batal digunakan di kuliah saya. Secara teknis tidak bermasalah. Tapi ternyata banyak mahasiswa yang tidak memiliki smartphone dan SMS twitter belum reliable. Akibatnya saat awal kuliah mahasiswa sibuk saling pinjam handphone dan notebook.
3 Comments »
RSS feed for comments on this post. TrackBack URI
Leave a Reply
Blog at WordPress.com. | Theme: Pool by Borja Fernandez.
Entries and comments feeds.
haha. maaf oot,.
tadi saya quote :
karena saya inget punya postingan ini: http://jurnal.snydez.com/id/1278/bangsa-pemalas-melahirkan-bangsa-kreatif
Comment by snydez— 10 February 2011 #
Hehe.. sebenarnya yg umum itu: “Necessity is the mother of invention” ya dimodif dikit lah
Comment by yudiwbs— 10 February 2011 #
Saya sangat tertarik dengan tulisan bapak ini. Saya mahasiswa informatika saya mohon ijin dan bimbingan buat coba sms gateway dengan twiter bapak. Mohon bimbingan……
Jika bapak berkenan mohon sharing referensi ke email saya pak….
terima kasih
luck
Comment by zaki— 18 March 2011 #