From c6b94ee31c047a94568ca942a76ea4e643cf87c8 Mon Sep 17 00:00:00 2001 From: Nathan Cannon Date: Sun, 4 Oct 2015 02:41:16 +0100 Subject: [PATCH] Created webapp for reviewing WaniKani burned items. --- .gitignore | 110 +++++++++++++++++++++++ static/burned.png | Bin 0 -> 18163 bytes static/style.css | 39 +++++++++ static/wanakana.min.js | 1 + templates/quiz.html | 127 +++++++++++++++++++++++++++ templates/welcome.html | 52 +++++++++++ wanikaniburned.py | 195 +++++++++++++++++++++++++++++++++++++++++ 7 files changed, 524 insertions(+) create mode 100644 .gitignore create mode 100644 static/burned.png create mode 100644 static/style.css create mode 100644 static/wanakana.min.js create mode 100644 templates/quiz.html create mode 100644 templates/welcome.html create mode 100644 wanikaniburned.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..484d453 --- /dev/null +++ b/.gitignore @@ -0,0 +1,110 @@ +# Created by .ignore support plugin (hsz.mobi) +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio + +*.iml + +## Directory-based project format: +.idea/ +# if you remove the above rule, at least ignore the following: + +# User-specific stuff: +# .idea/workspace.xml +# .idea/tasks.xml +# .idea/dictionaries + +# Sensitive or high-churn files: +# .idea/dataSources.ids +# .idea/dataSources.xml +# .idea/sqlDataSources.xml +# .idea/dynamic.xml +# .idea/uiDesigner.xml + +# Gradle: +# .idea/gradle.xml +# .idea/libraries + +# Mongo Explorer plugin: +# .idea/mongoSettings.xml + +## File-based project format: +*.ipr +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +### Python template +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover + +# Translations +*.mo +*.pot + +# Django stuff: +*.log + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +wanikani.db +config.py diff --git a/static/burned.png b/static/burned.png new file mode 100644 index 0000000000000000000000000000000000000000..a70400fa9e4d44722b6e7274f2f67aee55f45511 GIT binary patch literal 18163 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 KMNUMnLSTX?PQAGR literal 0 HcmV?d00001 diff --git a/static/style.css b/static/style.css new file mode 100644 index 0000000..0f3a74c --- /dev/null +++ b/static/style.css @@ -0,0 +1,39 @@ +.centered { + position: absolute; + top: 50%; + left:50%; + transform: translate(-50%,-50%); +} + +.padded { + padding: 5%; +} + +body{ + background-color: lightgray; +} + +.correct{ + background-color: greenyellow; +} + +.wrong{ + background-color: red; +} + +.question-size{ + font-size: 1000%; + color: white; +} + +.answer-size{ + font-size: 200%; + height: auto; + width: 100%; + text-align: center; +} + +.help-size{ + font-size: 200%; + color: white; +} \ No newline at end of file diff --git a/static/wanakana.min.js b/static/wanakana.min.js new file mode 100644 index 0000000..72916fc --- /dev/null +++ b/static/wanakana.min.js @@ -0,0 +1 @@ +var wanakana,__indexOf=[].indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(b in this&&this[b]===a)return b;return-1};wanakana=wanakana||{},wanakana.version="1.3.7","function"==typeof define&&define.amd&&define("wanakana",[],function(){return wanakana}),wanakana.LOWERCASE_START=97,wanakana.LOWERCASE_END=122,wanakana.UPPERCASE_START=65,wanakana.UPPERCASE_END=90,wanakana.HIRAGANA_START=12353,wanakana.HIRAGANA_END=12438,wanakana.KATAKANA_START=12449,wanakana.KATAKANA_END=12538,wanakana.LOWERCASE_FULLWIDTH_START=65345,wanakana.LOWERCASE_FULLWIDTH_END=65370,wanakana.UPPERCASE_FULLWIDTH_START=65313,wanakana.UPPERCASE_FULLWIDTH_END=65338,wanakana.defaultOptions={useObseleteKana:!1,IMEMode:!1},wanakana.bind=function(a){return a.addEventListener("input",wanakana._onInput)},wanakana.unbind=function(a){return a.removeEventListener("input",wanakana._onInput)},wanakana._onInput=function(a){var b,c,d,e,f,g;if(b=a.target,f=b.selectionStart,g=b.value.length,d=wanakana._convertFullwidthCharsToASCII(b.value),c=wanakana.toKana(d,{IMEMode:!0}),d!==c){if(b.value=c,"number"==typeof b.selectionStart)return b.selectionStart=b.selectionEnd=b.value.length;if("undefined"!=typeof b.createTextRange)return b.focus(),e=b.createTextRange(),e.collapse(!1),e.select()}},wanakana._extend=function(a,b){var c;if(null==a)return b;for(c in b)null==a[c]&&null!=b[c]&&(a[c]=b[c]);return a},wanakana._isCharInRange=function(a,b,c){var d;return d=a.charCodeAt(0),d>=b&&c>=d},wanakana._isCharVowel=function(a,b){var c;return null==b&&(b=!0),c=b?/[aeiouy]/:/[aeiou]/,-1!==a.toLowerCase().charAt(0).search(c)},wanakana._isCharConsonant=function(a,b){var c;return null==b&&(b=!0),c=b?/[bcdfghjklmnpqrstvwxyz]/:/[bcdfghjklmnpqrstvwxz]/,-1!==a.toLowerCase().charAt(0).search(c)},wanakana._isCharKatakana=function(a){return wanakana._isCharInRange(a,wanakana.KATAKANA_START,wanakana.KATAKANA_END)},wanakana._isCharHiragana=function(a){return wanakana._isCharInRange(a,wanakana.HIRAGANA_START,wanakana.HIRAGANA_END)},wanakana._isCharKana=function(a){return wanakana._isCharHiragana(a)||wanakana._isCharKatakana(a)},wanakana._isCharNotKana=function(a){return!wanakana._isCharHiragana(a)&&!wanakana._isCharKatakana(a)},wanakana._convertFullwidthCharsToASCII=function(a){var b,c,d,e,f,g;for(c=a.split(""),e=f=0,g=c.length;g>f;e=++f)b=c[e],d=b.charCodeAt(0),wanakana._isCharInRange(b,wanakana.LOWERCASE_FULLWIDTH_START,wanakana.LOWERCASE_FULLWIDTH_END)&&(c[e]=String.fromCharCode(d-wanakana.LOWERCASE_FULLWIDTH_START+wanakana.LOWERCASE_START)),wanakana._isCharInRange(b,wanakana.UPPERCASE_FULLWIDTH_START,wanakana.UPPERCASE_FULLWIDTH_END)&&c[e](String.fromCharCode(d-wanakana.UPPERCASE_FULLWIDTH_START+wanakana.UPPERCASE_START));return c.join("")},wanakana._katakanaToHiragana=function(a){var b,c,d,e,f,g,h;for(c=[],h=a.split(""),f=0,g=h.length;g>f;f++)e=h[f],wanakana._isCharKatakana(e)?(b=e.charCodeAt(0),b+=wanakana.HIRAGANA_START-wanakana.KATAKANA_START,d=String.fromCharCode(b),c.push(d)):c.push(e);return c.join("")},wanakana._hiraganaToKatakana=function(a){var b,c,d,e,f,g,h;for(d=[],h=a.split(""),f=0,g=h.length;g>f;f++)c=h[f],wanakana._isCharHiragana(c)?(b=c.charCodeAt(0),b+=wanakana.KATAKANA_START-wanakana.HIRAGANA_START,e=String.fromCharCode(b),d.push(e)):d.push(c);return d.join("")},wanakana._hiraganaToRomaji=function(a,b){var c,d,e,f,g,h,i,j,k,l;for(b=wanakana._extend(b,wanakana.defaultOptions),g=a.length,k=[],e=0,d=0,h=2,f=function(){return a.substr(e,d)},j=function(){return d=Math.min(h,g-e)};g>e;){for(j();d>0;){if(c=f(),wanakana.isKatakana(c)&&(c=wanakana._katakanaToHiragana(c)),"っ"===c.charAt(0)&&1===d&&g-1>e){i=!0,l="";break}if(l=wanakana.J_to_R[c],null!=l&&i&&(l=l.charAt(0).concat(l),i=!1),null!=l)break;d--}null==l&&(l=c),k.push(l),e+=d||1}return k.join("")},wanakana._romajiToHiragana=function(a,b){return wanakana._romajiToKana(a,b,!0)},wanakana._romajiToKana=function(a,b,c){var d,e,f,g,h,i,j,k,l,m;for(null==c&&(c=!1),b=wanakana._extend(b,wanakana.defaultOptions),l=a.length,j=[],g=0,m=3,h=function(){return a.substr(g,f)},i=function(a){return wanakana._isCharInRange(a,wanakana.UPPERCASE_START,wanakana.UPPERCASE_END)};l>g;){for(f=Math.min(m,l-g);f>0;){if(d=h(),e=d.toLowerCase(),__indexOf.call(wanakana.FOUR_CHARACTER_EDGE_CASES,e)>=0&&l-g>=4)f++,d=h(),e=d.toLowerCase();else{if("n"===e.charAt(0)){if(b.IMEMode&&"'"===e.charAt(1)&&2===f){k="ん";break}wanakana._isCharConsonant(e.charAt(1),!1)&&wanakana._isCharVowel(e.charAt(2))&&(f=1,d=h(),e=d.toLowerCase())}"n"!==e.charAt(0)&&wanakana._isCharConsonant(e.charAt(0))&&d.charAt(0)===d.charAt(1)&&(f=1,e=d=wanakana._isCharInRange(d.charAt(0),wanakana.UPPERCASE_START,wanakana.UPPERCASE_END)?"ッ":"っ")}if(k=wanakana.R_to_J[e],null!=k)break;4===f?f-=2:f--}null==k&&(d=wanakana._convertPunctuation(d),k=d),(null!=b?b.useObseleteKana:void 0)&&("wi"===e&&(k="ゐ"),"we"===e&&(k="ゑ")),b.IMEMode&&"n"===e.charAt(0)&&("y"===a.charAt(g+1).toLowerCase()&&wanakana._isCharVowel(a.charAt(g+2))===!1||g===l-1||wanakana.isKana(a.charAt(g+1)))&&(k=d.charAt(0)),c||i(d.charAt(0))&&(k=wanakana._hiraganaToKatakana(k)),j.push(k),g+=f||1}return j.join("")},wanakana._convertPunctuation=function(a){return" "===a?" ":"-"===a?"ー":a},wanakana.isHiragana=function(a){var b;return b=a.split(""),b.every(wanakana._isCharHiragana)},wanakana.isKatakana=function(a){var b;return b=a.split(""),b.every(wanakana._isCharKatakana)},wanakana.isKana=function(a){var b;return b=a.split(""),b.every(function(a){return wanakana.isHiragana(a)||wanakana.isKatakana(a)})},wanakana.isRomaji=function(a){var b;return b=a.split(""),b.every(function(a){return!wanakana.isHiragana(a)&&!wanakana.isKatakana(a)})},wanakana.toHiragana=function(a,b){return wanakana.isRomaji(a)?a=wanakana._romajiToHiragana(a,b):wanakana.isKatakana(a)?a=wanakana._katakanaToHiragana(a,b):a},wanakana.toKatakana=function(a,b){return wanakana.isHiragana(a)?a=wanakana._hiraganaToKatakana(a,b):wanakana.isRomaji(a)?(a=wanakana._romajiToHiragana(a,b),a=wanakana._hiraganaToKatakana(a,b)):a},wanakana.toKana=function(a,b){return a=wanakana._romajiToKana(a,b)},wanakana.toRomaji=function(a){return a=wanakana._hiraganaToRomaji(a)},wanakana.R_to_J={a:"あ",i:"い",u:"う",e:"え",o:"お",yi:"い",wu:"う",whu:"う",xa:"ぁ",xi:"ぃ",xu:"ぅ",xe:"ぇ",xo:"ぉ",xyi:"ぃ",xye:"ぇ",ye:"いぇ",wha:"うぁ",whi:"うぃ",whe:"うぇ",who:"うぉ",wi:"うぃ",we:"うぇ",va:"ゔぁ",vi:"ゔぃ",vu:"ゔ",ve:"ゔぇ",vo:"ゔぉ",vya:"ゔゃ",vyi:"ゔぃ",vyu:"ゔゅ",vye:"ゔぇ",vyo:"ゔょ",ka:"か",ki:"き",ku:"く",ke:"け",ko:"こ",lka:"ヵ",lke:"ヶ",xka:"ヵ",xke:"ヶ",kya:"きゃ",kyi:"きぃ",kyu:"きゅ",kye:"きぇ",kyo:"きょ",ca:"か",ci:"き",cu:"く",ce:"け",co:"こ",lca:"ヵ",lce:"ヶ",xca:"ヵ",xce:"ヶ",qya:"くゃ",qyu:"くゅ",qyo:"くょ",qwa:"くぁ",qwi:"くぃ",qwu:"くぅ",qwe:"くぇ",qwo:"くぉ",qa:"くぁ",qi:"くぃ",qe:"くぇ",qo:"くぉ",kwa:"くぁ",qyi:"くぃ",qye:"くぇ",ga:"が",gi:"ぎ",gu:"ぐ",ge:"げ",go:"ご",gya:"ぎゃ",gyi:"ぎぃ",gyu:"ぎゅ",gye:"ぎぇ",gyo:"ぎょ",gwa:"ぐぁ",gwi:"ぐぃ",gwu:"ぐぅ",gwe:"ぐぇ",gwo:"ぐぉ",sa:"さ",si:"し",shi:"し",su:"す",se:"せ",so:"そ",za:"ざ",zi:"じ",zu:"ず",ze:"ぜ",zo:"ぞ",ji:"じ",sya:"しゃ",syi:"しぃ",syu:"しゅ",sye:"しぇ",syo:"しょ",sha:"しゃ",shu:"しゅ",she:"しぇ",sho:"しょ",shya:"しゃ",shyu:"しゅ",shye:"しぇ",shyo:"しょ",swa:"すぁ",swi:"すぃ",swu:"すぅ",swe:"すぇ",swo:"すぉ",zya:"じゃ",zyi:"じぃ",zyu:"じゅ",zye:"じぇ",zyo:"じょ",ja:"じゃ",ju:"じゅ",je:"じぇ",jo:"じょ",jya:"じゃ",jyi:"じぃ",jyu:"じゅ",jye:"じぇ",jyo:"じょ",ta:"た",ti:"ち",tu:"つ",te:"て",to:"と",chi:"ち",tsu:"つ",ltu:"っ",xtu:"っ",tya:"ちゃ",tyi:"ちぃ",tyu:"ちゅ",tye:"ちぇ",tyo:"ちょ",cha:"ちゃ",chu:"ちゅ",che:"ちぇ",cho:"ちょ",cya:"ちゃ",cyi:"ちぃ",cyu:"ちゅ",cye:"ちぇ",cyo:"ちょ",chya:"ちゃ",chyu:"ちゅ",chye:"ちぇ",chyo:"ちょ",tsa:"つぁ",tsi:"つぃ",tse:"つぇ",tso:"つぉ",tha:"てゃ",thi:"てぃ",thu:"てゅ",the:"てぇ",tho:"てょ",twa:"とぁ",twi:"とぃ",twu:"とぅ",twe:"とぇ",two:"とぉ",da:"だ",di:"ぢ",du:"づ",de:"で","do":"ど",dya:"ぢゃ",dyi:"ぢぃ",dyu:"ぢゅ",dye:"ぢぇ",dyo:"ぢょ",dha:"でゃ",dhi:"でぃ",dhu:"でゅ",dhe:"でぇ",dho:"でょ",dwa:"どぁ",dwi:"どぃ",dwu:"どぅ",dwe:"どぇ",dwo:"どぉ",na:"な",ni:"に",nu:"ぬ",ne:"ね",no:"の",nya:"にゃ",nyi:"にぃ",nyu:"にゅ",nye:"にぇ",nyo:"にょ",ha:"は",hi:"ひ",hu:"ふ",he:"へ",ho:"ほ",fu:"ふ",hya:"ひゃ",hyi:"ひぃ",hyu:"ひゅ",hye:"ひぇ",hyo:"ひょ",fya:"ふゃ",fyu:"ふゅ",fyo:"ふょ",fwa:"ふぁ",fwi:"ふぃ",fwu:"ふぅ",fwe:"ふぇ",fwo:"ふぉ",fa:"ふぁ",fi:"ふぃ",fe:"ふぇ",fo:"ふぉ",fyi:"ふぃ",fye:"ふぇ",ba:"ば",bi:"び",bu:"ぶ",be:"べ",bo:"ぼ",bya:"びゃ",byi:"びぃ",byu:"びゅ",bye:"びぇ",byo:"びょ",pa:"ぱ",pi:"ぴ",pu:"ぷ",pe:"ぺ",po:"ぽ",pya:"ぴゃ",pyi:"ぴぃ",pyu:"ぴゅ",pye:"ぴぇ",pyo:"ぴょ",ma:"ま",mi:"み",mu:"む",me:"め",mo:"も",mya:"みゃ",myi:"みぃ",myu:"みゅ",mye:"みぇ",myo:"みょ",ya:"や",yu:"ゆ",yo:"よ",xya:"ゃ",xyu:"ゅ",xyo:"ょ",ra:"ら",ri:"り",ru:"る",re:"れ",ro:"ろ",rya:"りゃ",ryi:"りぃ",ryu:"りゅ",rye:"りぇ",ryo:"りょ",la:"ら",li:"り",lu:"る",le:"れ",lo:"ろ",lya:"りゃ",lyi:"りぃ",lyu:"りゅ",lye:"りぇ",lyo:"りょ",wa:"わ",wo:"を",lwe:"ゎ",xwa:"ゎ",n:"ん",nn:"ん","n ":"ん",xn:"ん",ltsu:"っ"},wanakana.FOUR_CHARACTER_EDGE_CASES=["lts","chy","shy"],wanakana.J_to_R={"あ":"a","い":"i","う":"u","え":"e","お":"o","ゔぁ":"va","ゔぃ":"vi","ゔ":"vu","ゔぇ":"ve","ゔぉ":"vo","か":"ka","き":"ki","きゃ":"kya","きぃ":"kyi","きゅ":"kyu","く":"ku","け":"ke","こ":"ko","が":"ga","ぎ":"gi","ぐ":"gu","げ":"ge","ご":"go","ぎゃ":"gya","ぎぃ":"gyi","ぎゅ":"gyu","ぎぇ":"gye","ぎょ":"gyo","さ":"sa","す":"su","せ":"se","そ":"so","ざ":"za","ず":"zu","ぜ":"ze","ぞ":"zo","し":"shi","しゃ":"sha","しゅ":"shu","しょ":"sho","じ":"ji","じゃ":"ja","じゅ":"ju","じょ":"jo","た":"ta","ち":"chi","ちゃ":"cha","ちゅ":"chu","ちょ":"cho","つ":"tsu","て":"te","と":"to","だ":"da","ぢ":"di","づ":"du","で":"de","ど":"do","な":"na","に":"ni","にゃ":"nya","にゅ":"nyu","にょ":"nyo","ぬ":"nu","ね":"ne","の":"no","は":"ha","ひ":"hi","ふ":"fu","へ":"he","ほ":"ho","ひゃ":"hya","ひゅ":"hyu","ひょ":"hyo","ふぁ":"fa","ふぃ":"fi","ふぇ":"fe","ふぉ":"fo","ば":"ba","び":"bi","ぶ":"bu","べ":"be","ぼ":"bo","びゃ":"bya","びゅ":"byu","びょ":"byo","ぱ":"pa","ぴ":"pi","ぷ":"pu","ぺ":"pe","ぽ":"po","ぴゃ":"pya","ぴゅ":"pyu","ぴょ":"pyo","ま":"ma","み":"mi","む":"mu","め":"me","も":"mo","みゃ":"mya","みゅ":"myu","みょ":"myo","や":"ya","ゆ":"yu","よ":"yo","ら":"ra","り":"ri","る":"ru","れ":"re","ろ":"ro","りゃ":"rya","りゅ":"ryu","りょ":"ryo","わ":"wa","を":"wo","ん":"n","ゐ":"wi","ゑ":"we","きぇ":"kye","きょ":"kyo","じぃ":"jyi","じぇ":"jye","ちぃ":"cyi","ちぇ":"che","ひぃ":"hyi","ひぇ":"hye","びぃ":"byi","びぇ":"bye","ぴぃ":"pyi","ぴぇ":"pye","みぇ":"mye","みぃ":"myi","りぃ":"ryi","りぇ":"rye","にぃ":"nyi","にぇ":"nye","しぃ":"syi","しぇ":"she","いぇ":"ye","うぁ":"wha","うぉ":"who","うぃ":"wi","うぇ":"we","ゔゃ":"vya","ゔゅ":"vyu","ゔょ":"vyo","すぁ":"swa","すぃ":"swi","すぅ":"swu","すぇ":"swe","すぉ":"swo","くゃ":"qya","くゅ":"qyu","くょ":"qyo","くぁ":"qwa","くぃ":"qwi","くぅ":"qwu","くぇ":"qwe","くぉ":"qwo","ぐぁ":"gwa","ぐぃ":"gwi","ぐぅ":"gwu","ぐぇ":"gwe","ぐぉ":"gwo","つぁ":"tsa","つぃ":"tsi","つぇ":"tse","つぉ":"tso","てゃ":"tha","てぃ":"thi","てゅ":"thu","てぇ":"the","てょ":"tho","とぁ":"twa","とぃ":"twi","とぅ":"twu","とぇ":"twe","とぉ":"two","ぢゃ":"dya","ぢぃ":"dyi","ぢゅ":"dyu","ぢぇ":"dye","ぢょ":"dyo","でゃ":"dha","でぃ":"dhi","でゅ":"dhu","でぇ":"dhe","でょ":"dho","どぁ":"dwa","どぃ":"dwi","どぅ":"dwu","どぇ":"dwe","どぉ":"dwo","ふぅ":"fwu","ふゃ":"fya","ふゅ":"fyu","ふょ":"fyo","ぁ":"a","ぃ":"i","ぇ":"e","ぅ":"u","ぉ":"o","ゃ":"ya","ゅ":"yu","ょ":"yo","っ":"","ゕ":"ka","ゖ":"ka","ゎ":"wa"," ":" ","んあ":"n'a","んい":"n'i","んう":"n'u","んえ":"n'e","んお":"n'o","んや":"n'ya","んゆ":"n'yu","んよ":"n'yo"}; \ No newline at end of file diff --git a/templates/quiz.html b/templates/quiz.html new file mode 100644 index 0000000..155f2b4 --- /dev/null +++ b/templates/quiz.html @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + +

+
+
+

+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+ + + \ No newline at end of file diff --git a/templates/welcome.html b/templates/welcome.html new file mode 100644 index 0000000..10d66d5 --- /dev/null +++ b/templates/welcome.html @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+ {{ form.csrf_token }} + {{ form.api_key(**{'class':'form-control','placeholder':'Insert API Key'}) }} + + + +
+
+
+ {% for error in form.api_key.errors %} + + {% endfor %} + {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} + {% for category, message in messages %} + + {% endfor %} + {% endif %} + {% endwith %} +
+
+
+ + \ No newline at end of file diff --git a/wanikaniburned.py b/wanikaniburned.py new file mode 100644 index 0000000..17d3e27 --- /dev/null +++ b/wanikaniburned.py @@ -0,0 +1,195 @@ +import json +import random +from flask import Flask, render_template, redirect, url_for, jsonify, flash +from flask.ext.login import LoginManager, login_user, login_required, current_user, logout_user, login_fresh +from flask.ext.sqlalchemy import SQLAlchemy +from flask.ext.wtf import Form +import requests +from wtforms import StringField +from wtforms.validators import DataRequired +from datetime import datetime + +app = Flask(__name__) +app.config.from_pyfile('config.py') +login_manager = LoginManager() +login_manager.init_app(app) +db = SQLAlchemy(app) + + +class LoginForm(Form): + api_key = StringField('api_key', validators=[DataRequired()]) + + +class User(db.Model): + __tablename__ = 'users' + api_key = db.Column(db.String, unique=True, primary_key=True) + radicals = db.Column(db.String) + kanji = db.Column(db.String) + vocabulary = db.Column(db.String) + username = db.Column(db.String) + gravatar = db.Column(db.String) + last_updated = db.Column(db.DateTime) + + def __init__(self, api_key): + self.api_key = api_key + self.last_updated = datetime.utcnow() + self.parse_radicals_and_userdata() + self.parse_kanji() + self.parse_vocabulary() + db.session.add(self) + db.session.commit() + + def is_authenticated(self): + return True + + def is_active(self): + return True + + def is_anonymous(self): + return False + + def get_id(self): + return str(self.api_key) + + def parse_radicals_and_userdata(self): + response = requests.get("https://www.wanikani.com/api/user/" + self.api_key + "/radicals/") + response.raise_for_status() + data = response.json() + if data.get('error'): + raise ValueError(data['error']['message']) + items = [] + self.username = data['user_information']['username'] + self.gravatar = data['user_information']['gravatar'] + if data.get('requested_information'): + for item in data['requested_information']: + if item.get('user_specific') and item['user_specific']['burned']: + items.append({'character': item['character'], 'meaning': item['meaning'], 'image': item['image']}) + self.radicals = json.dumps(items) + + def parse_kanji(self): + response = requests.get("https://www.wanikani.com/api/user/" + self.api_key + "/kanji/") + response.raise_for_status() + data = response.json() + if data.get('error'): + raise ValueError(data['error']['message']) + items = [] + if data.get('requested_information'): + for item in data['requested_information']: + if item.get('user_specific') and item['user_specific']['burned']: + items.append({'character': item['character'], 'meaning': item['meaning'], 'onyomi': item['onyomi'], + 'kunyomi': item['kunyomi']}) + self.kanji = json.dumps(items) + + def parse_vocabulary(self): + response = requests.get("https://www.wanikani.com/api/user/" + self.api_key + "/vocabulary/") + response.raise_for_status() + data = response.json() + if data.get('error'): + raise ValueError(data['error']['message']) + items = [] + if data.get('requested_information'): + for item in data['requested_information']['general']: + if item.get('user_specific') and item['user_specific']['burned']: + items.append({'character': item['character'], 'meaning': item['meaning'], 'kana': item['kana']}) + self.vocabulary = json.dumps(items) + + def update_all(self): + self.parse_radicals_and_userdata() + self.parse_kanji() + self.parse_vocabulary() + self.last_updated = datetime.utcnow() + db.session.add(self) + db.session.commit() + + +@login_manager.user_loader +def load_user(api_key): + return User.query.get(str(api_key)) + + +@app.route('/', methods=('GET', 'POST')) +def show_home(): + if current_user.is_authenticated: + return redirect(url_for('show_quiz')) + form = LoginForm() + if form.validate_on_submit(): + user = User.query.get(str(form.api_key.data)) + if user: + login_user(user) + return redirect(url_for('show_quiz')) + else: + try: + new_user = User(str(form.api_key.data)) + login_user(new_user) + return redirect(url_for('show_quiz')) + except ValueError as err: + flash(err) + return render_template("welcome.html", form=form) + return render_template("welcome.html", form=form) + + +@login_required +@app.route('/quiz') +def show_quiz(): + if not login_fresh(): + if User.query.get(current_user.api_key): + return render_template("quiz.html") + else: + logout_user() + return redirect(url_for('show_home')) + return render_template("quiz.html") + + +@app.route('/quiz_item') +@login_required +def get_quiz(): + choices = [] + if current_user.radicals: + choices.append('radical') + if current_user.kanji: + choices.append('kanji') + if current_user.vocabulary: + choices.append('vocabulary') + selected_type = random.choice(choices) + if selected_type is 'radical': + selected_item = random.choice(json.loads(current_user.radicals)) + if selected_item['image']: + return jsonify(item_type='radical', question=selected_item['image'], answer=selected_item['meaning']) + else: + return jsonify(item_type='radical', question=selected_item['character'], answer=selected_item['meaning']) + elif selected_type is 'kanji': + selected_item = random.choice(json.loads(current_user.kanji)) + made_answer = "" + if selected_item['onyomi'] and selected_item['kunyomi']: + made_answer = selected_item['onyomi'] + ',' + selected_item['kunyomi'].replace('.*', '') + elif selected_item['onyomi']: + made_answer = selected_item['onyomi'] + elif selected_item['kunyomi']: + made_answer = selected_item['kunyomi'].replace('.*', '') + return jsonify(item_type='kanji', question=selected_item['character'], + answer=made_answer) + else: + selected_item = random.choice(json.loads(current_user.vocabulary)) + return jsonify(item_type='vocabulary', question=selected_item['character'], answer=selected_item['kana']) + + +@app.route('/refresh', methods=['POST']) +def refresh_api(): + current_user.update_all() + return "202" + + +@app.route('/logout') +def logout(): + logout_user() + return redirect(url_for('show_home')) + + +@login_manager.unauthorized_handler +def unauthorized(): + return redirect(url_for('show_home')) + +if __name__ == '__main__': + db.create_all() + app.debug = True + app.run()