2
0

app.py 143 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665
  1. from bottle import *
  2. from bottle.ext import beaker
  3. import json
  4. import sqlite3
  5. import bcrypt
  6. import os
  7. import difflib
  8. from css_html_js_minify import html_minify
  9. from multiprocessing import Process
  10. try:
  11. json_data = open('set.json').read()
  12. set_data = json.loads(json_data)
  13. except:
  14. new_json = []
  15. print('DB 이름 : ', end = '')
  16. new_json += [input()]
  17. print('위키 포트 : ', end = '')
  18. new_json += [input()]
  19. with open("set.json", "w") as f:
  20. f.write('{ "db" : "' + new_json[0] + '", "port" : "' + new_json[1] + '" }')
  21. json_data = open('set.json').read()
  22. set_data = json.loads(json_data)
  23. conn = sqlite3.connect(set_data['db'] + '.db')
  24. curs = conn.cursor()
  25. session_opts = {
  26. 'session.type': 'file',
  27. 'session.data_dir': './app_session/',
  28. 'session.auto': 1
  29. }
  30. app = beaker.middleware.SessionMiddleware(app(), session_opts)
  31. from func import *
  32. BaseRequest.MEMFILE_MAX = 1000 ** 4
  33. def redirect(data):
  34. return('<meta http-equiv="refresh" content="0;url=' + data + '" />')
  35. r_ver = '2.3.5'
  36. p_ver = ''
  37. try:
  38. curs.execute("select title from data limit 1")
  39. try:
  40. curs.execute('select new from move limit 1')
  41. except:
  42. curs.execute("create table move(origin text, new text, date text, who text, send text)")
  43. print('move 테이블 생성')
  44. curs.execute('select data from other where name = "skin"')
  45. s_d = curs.fetchall()
  46. if(s_d):
  47. if(os.path.exists(os.path.abspath('./views/' + s_d[0][0] + '/index.tpl')) == 1):
  48. TEMPLATE_PATH.insert(0, './views/' + s_d[0][0] + '/')
  49. else:
  50. TEMPLATE_PATH.insert(0, './views/yousoro/')
  51. else:
  52. TEMPLATE_PATH.insert(0, './views/yousoro/')
  53. try:
  54. curs.execute('select name from alarm limit 1')
  55. except:
  56. curs.execute("create table alarm(name text, data text, date text)")
  57. print('alarm 테이블 생성')
  58. try:
  59. curs.execute('select name from ua_d limit 1')
  60. except:
  61. curs.execute("create table ua_d(name text, ip text, ua text, today text, sub text)")
  62. print('ua_d 테이블 생성')
  63. try:
  64. curs.execute('select user, ip, today from login')
  65. lo_d = curs.fetchall()
  66. for m_lo in lo_d:
  67. curs.execute("insert into ua_d (name, ip, ua, today, sub) values (?, ?, '', ?, '')", [m_lo[0], m_lo[1], m_lo[2]])
  68. curs.execute("drop table login")
  69. print('login 테이블 삭제')
  70. except:
  71. pass
  72. conn.commit()
  73. except:
  74. pass
  75. @route('/setup', method=['GET', 'POST'])
  76. def setup():
  77. try:
  78. curs.execute("select title from data limit 1")
  79. except:
  80. try:
  81. curs.execute("create table data(title text, data text, acl text)")
  82. curs.execute("create table history(id text, title text, data text, date text, ip text, send text, leng text)")
  83. curs.execute("create table rd(title text, sub text, date text)")
  84. curs.execute("create table user(id text, pw text, acl text)")
  85. curs.execute("create table ban(block text, end text, why text, band text)")
  86. curs.execute("create table topic(id text, title text, sub text, data text, date text, ip text, block text, top text)")
  87. curs.execute("create table stop(title text, sub text, close text)")
  88. curs.execute("create table rb(block text, end text, today text, blocker text, why text)")
  89. curs.execute("create table back(title text, link text, type text)")
  90. curs.execute("create table cat(title text, cat text)")
  91. curs.execute("create table hidhi(title text, re text)")
  92. curs.execute("create table agreedis(title text, sub text)")
  93. curs.execute("create table custom(user text, css text)")
  94. curs.execute("create table other(name text, data text)")
  95. curs.execute("create table alist(name text, acl text)")
  96. curs.execute("create table re_admin(who text, what text, time text)")
  97. curs.execute("create table move(origin text, new text, date text, who text, send text)")
  98. curs.execute("create table alarm(name text, data text, date text)")
  99. curs.execute("create table ua_d(name text, ip text, ua text, today text, sub text)")
  100. curs.execute("insert into alist (name, acl) values ('소유자', 'owner')")
  101. conn.commit()
  102. except:
  103. pass
  104. return(redirect('/'))
  105. @route('/del_alarm')
  106. def del_alarm():
  107. curs.execute("delete from alarm where name = ?", [ip_check()])
  108. conn.commit()
  109. return(redirect('/alarm'))
  110. @route('/alarm')
  111. def alarm():
  112. ip = ip_check()
  113. if(re.search('(?:\.|:)', ip)):
  114. return(redirect('/login'))
  115. da = '<ul>'
  116. curs.execute("select data, date from alarm where name = ? order by date desc", [ip])
  117. dt = curs.fetchall()
  118. if(dt):
  119. da = '<a href="/del_alarm">(알람 삭제)</a><br><br>' + da
  120. for do in dt:
  121. da += '<li>' + do[0] + ' / ' + do[1] + '</li>'
  122. else:
  123. da += '<li>알림이 없습니다.</li>'
  124. da += '</ul>'
  125. return(
  126. html_minify(
  127. template('index',
  128. imp = ['알림', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  129. data = da,
  130. menu = [['user', '사용자']]
  131. )
  132. )
  133. )
  134. @route('/edit_set', method=['POST', 'GET'])
  135. @route('/edit_set/<num:int>', method=['POST', 'GET'])
  136. def edit_set(num = 0):
  137. if(num == 0):
  138. return(
  139. html_minify(
  140. template('index',
  141. imp = ['설정 편집', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  142. data = '<ul> \
  143. <li><a href="/edit_set/1">기본 설정</a></li> \
  144. <li><a href="/edit_set/2">문구 관련</a></li> \
  145. </ul>',
  146. menu = [['manager', '관리자']]
  147. )
  148. )
  149. )
  150. elif(num == 1):
  151. if(admin_check(None, 'edit_set') == 1):
  152. if(request.method == 'POST'):
  153. curs.execute("update other set data = ? where name = ?", [request.forms.name, 'name'])
  154. curs.execute("update other set data = ? where name = 'frontpage'", [request.forms.frontpage])
  155. curs.execute("update other set data = ? where name = 'license'", [request.forms.license])
  156. curs.execute("update other set data = ? where name = 'upload'", [request.forms.upload])
  157. curs.execute("update other set data = ? where name = 'skin'", [request.forms.skin])
  158. conn.commit()
  159. return(redirect('/edit_set/1'))
  160. else:
  161. i_list = ['name', 'frontpage', 'license', 'upload', 'skin']
  162. n_list = ['무명위키', '위키:대문', 'CC 0', '2', '']
  163. d_list = []
  164. x = 0
  165. for i in i_list:
  166. curs.execute('select data from other where name = ?', [i])
  167. sql_d = curs.fetchall()
  168. if(sql_d):
  169. d_list += [sql_d[0][0]]
  170. else:
  171. curs.execute('insert into other (name, data) values (?, ?)', [i, n_list[x]])
  172. d_list += [n_list[x]]
  173. x += 1
  174. conn.commit()
  175. return(
  176. html_minify(
  177. template('index',
  178. imp = ['기본 설정', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  179. data = '<form method="post"> \
  180. <span>위키 이름 (기본 : 무명위키)</span> \
  181. <br> \
  182. <br> \
  183. <input placeholder="위키 이름" style="width: 100%;" type="text" name="name" value="' + d_list[0] + '"> \
  184. <br> \
  185. <br> \
  186. <span>시작 페이지 (기본 : 위키:대문)</span> \
  187. <br> \
  188. <br> \
  189. <input placeholder="시작 페이지" style="width: 100%;" type="text" name="frontpage" value="' + d_list[1] + '"> \
  190. <br> \
  191. <br> \
  192. <span>라이선스 (기본 : CC 0)</span> \
  193. <br> \
  194. <br> \
  195. <input placeholder="라이선스" style="width: 100%;" type="text" name="license" value="' + d_list[2] + '"> \
  196. <br> \
  197. <br> \
  198. <span>파일 용량 한도 (기본 : 2)</span> \
  199. <br> \
  200. <br> \
  201. <input placeholder="파일 용량 한도" style="width: 100%;" type="text" name="upload" value="' + d_list[3] + '"> \
  202. <br> \
  203. <br> \
  204. <span>스킨 (기본 : yousoro)</span> \
  205. <br> \
  206. <br> \
  207. <input placeholder="스킨" style="width: 100%;" type="text" name="skin" value="' + d_list[4] + '"> \
  208. <br> \
  209. <br> \
  210. <button class="btn btn-primary" type="submit">저장</button> \
  211. </form>',
  212. menu = [['edit_set', '설정 편집']]
  213. )
  214. )
  215. )
  216. elif(num == 2):
  217. if(admin_check(None, 'edit_set') == 1):
  218. if(request.method == 'POST'):
  219. curs.execute("update other set data = ? where name = ?", [request.forms.contract, 'contract'])
  220. conn.commit()
  221. return(redirect('/edit_set/2'))
  222. else:
  223. i_list = ['contract']
  224. n_list = ['']
  225. d_list = []
  226. x = 0
  227. for i in i_list:
  228. curs.execute('select data from other where name = ?', [i])
  229. sql_d = curs.fetchall()
  230. if(sql_d):
  231. d_list += [sql_d[0][0]]
  232. else:
  233. curs.execute('insert into other (name, data) values (?, ?)', [i, n_list[x]])
  234. d_list += [n_list[x]]
  235. x += 1
  236. conn.commit()
  237. return(
  238. html_minify(
  239. template('index',
  240. imp = ['문구 관련', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  241. data = '<form method="post"> \
  242. <span>가입 약관</span> \
  243. <br> \
  244. <br> \
  245. <input placeholder="가입 약관" style="width: 100%;" type="text" name="contract" value="' + d_list[0] + '"> \
  246. <br> \
  247. <br> \
  248. <button class="btn btn-primary" type="submit">저장</button> \
  249. </form>',
  250. menu = [['edit_set', '설정 편집']]
  251. )
  252. )
  253. )
  254. else:
  255. return(redirect('/ban'))
  256. @route('/not_close_topic')
  257. def not_close_topic():
  258. div = '<ul>'
  259. i = 1
  260. curs.execute('select title, sub from rd order by date desc')
  261. n_list = curs.fetchall()
  262. for data in n_list:
  263. curs.execute('select * from stop where title = ? and sub = ? and close = "O"', [data[0], data[1]])
  264. is_close = curs.fetchall()
  265. if(not is_close):
  266. div += '<li>' + str(i) + '. <a href="/topic/' + url_pas(data[0]) + '/sub/' + url_pas(data[1]) + '">' + data[0] + ' (' + data[1] + ')</a></li>'
  267. i += 1
  268. div += '</ul>'
  269. return(
  270. html_minify(
  271. template('index',
  272. imp = ['열린 토론 목록', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  273. data = div,
  274. menu = [['manager', '관리자']]
  275. )
  276. )
  277. )
  278. @route('/image/<name:path>')
  279. def static(name = None):
  280. if(os.path.exists(os.path.join('image', name))):
  281. return(static_file(name, root = 'image'))
  282. else:
  283. return(redirect('/'))
  284. @route('/acl_list')
  285. def acl_list():
  286. div = '<ul>'
  287. i = 0
  288. curs.execute("select title, acl from data where acl = 'admin' or acl = 'user' order by acl desc")
  289. list_data = curs.fetchall()
  290. for data in list_data:
  291. if(not re.search('^사용자:', data[0])):
  292. if(data[1] == 'admin'):
  293. acl = '관리자'
  294. else:
  295. acl = '로그인'
  296. div += '<li>' + str(i + 1) + '. <a href="/w/' + url_pas(data[0]) + '">' + data[0] + '</a> (' + acl + ')</li>'
  297. i += 1
  298. div += '</ul>'
  299. return(
  300. html_minify(
  301. template('index',
  302. imp = ['ACL 문서 목록', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  303. data = div,
  304. menu = [['other', '기타']]
  305. )
  306. )
  307. )
  308. @route('/list_acl')
  309. def list_acl():
  310. div = '<ul>'
  311. i = 0
  312. curs.execute("select name, acl from alist order by name desc")
  313. list_data = curs.fetchall()
  314. for data in list_data:
  315. if(data[1] == 'ban'):
  316. acl = '차단'
  317. elif(data[1] == 'mdel'):
  318. acl = '많은 문서 삭제'
  319. elif(data[1] == 'toron'):
  320. acl = '토론 관리'
  321. elif(data[1] == 'check'):
  322. acl = '사용자 검사'
  323. elif(data[1] == 'acl'):
  324. acl = '문서 ACL'
  325. elif(data[1] == 'hidel'):
  326. acl = '역사 숨김'
  327. elif(data[1] == 'owner'):
  328. acl = '소유자'
  329. div += '<li>' + str(i + 1) + '. <a href="/admin_plus/' + url_pas(data[0]) + '">' + data[0] + '</a> (' + acl + ')</li>'
  330. i += 1
  331. div += '</ul><br><a href="/manager/8">(생성)</a>'
  332. return(
  333. html_minify(
  334. template('index',
  335. imp = ['ACL 목록', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  336. data = re.sub('^<ul></ul><br>', '', div),
  337. menu = [['manager', '관리자']]
  338. )
  339. )
  340. )
  341. @route('/admin_plus/<name:path>', method=['POST', 'GET'])
  342. def admin_plus(name = None):
  343. if(admin_check(None, 'admin_plus (' + name + ')') == 1):
  344. if(request.method == 'POST'):
  345. curs.execute("delete from alist where name = ?", [name])
  346. if(request.forms.ban):
  347. curs.execute("insert into alist (name, acl) values (?, 'ban')", [name])
  348. if(request.forms.mdel):
  349. curs.execute("insert into alist (name, acl) values (?, 'mdel')", [name])
  350. if(request.forms.toron):
  351. curs.execute("insert into alist (name, acl) values (?, 'toron')", [name])
  352. if(request.forms.check):
  353. curs.execute("insert into alist (name, acl) values (?, 'check')", [name])
  354. if(request.forms.acl):
  355. curs.execute("insert into alist (name, acl) values (?, 'acl')", [name])
  356. if(request.forms.hidel):
  357. curs.execute("insert into alist (name, acl) values (?, 'hidel')", [name])
  358. if(request.forms.owner):
  359. curs.execute("insert into alist (name, acl) values (?, 'owner')", [name])
  360. conn.commit()
  361. return(redirect('/admin_plus/' + url_pas(name)))
  362. else:
  363. curs.execute('select acl from alist where name = ?', [name])
  364. test = curs.fetchall()
  365. data = '<ul>'
  366. exist_list = ['', '', '', '', '', '', '']
  367. for go in test:
  368. if(go[0] == 'ban'):
  369. exist_list[0] = 'checked="checked"'
  370. elif(go[0] == 'mdel'):
  371. exist_list[1] = 'checked="checked"'
  372. elif(go[0] == 'toron'):
  373. exist_list[2] = 'checked="checked"'
  374. elif(go[0] == 'check'):
  375. exist_list[3] = 'checked="checked"'
  376. elif(go[0] == 'acl'):
  377. exist_list[4] = 'checked="checked"'
  378. elif(go[0] == 'hidel'):
  379. exist_list[5] = 'checked="checked"'
  380. elif(go[0] == 'owner'):
  381. exist_list[6] = 'checked="checked"'
  382. data += '<li><input type="checkbox" name="ban" ' + exist_list[0] + '> 차단</li>'
  383. data += '<li><input type="checkbox" name="mdel" ' + exist_list[1] + '> 많은 문서 삭제</li>'
  384. data += '<li><input type="checkbox" name="toron" ' + exist_list[2] + '> 토론 관리</li>'
  385. data += '<li><input type="checkbox" name="check" ' + exist_list[3] + '> 사용자 검사</li>'
  386. data += '<li><input type="checkbox" name="acl" ' + exist_list[4] + '> 문서 ACL</li>'
  387. data += '<li><input type="checkbox" name="hidel" ' + exist_list[5] + '> 역사 숨김</li>'
  388. data += '<li><input type="checkbox" name="owner" ' + exist_list[6] + '> 소유자</li></ul>'
  389. return(
  390. html_minify(
  391. template('index',
  392. imp = ['관리 그룹 추가', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  393. data = '<form method="post">' \
  394. + data + \
  395. '<div class="form-actions"> \
  396. <button class="btn btn-primary" type="submit">저장</button> \
  397. </div> \
  398. </form>',
  399. menu = [['manager', '관리자']]
  400. )
  401. )
  402. )
  403. else:
  404. return(redirect('/error/3'))
  405. @route('/admin_list')
  406. def admin_list():
  407. i = 1
  408. div = '<ul>'
  409. curs.execute("select id, acl from user where not acl = 'user'")
  410. user_data = curs.fetchall()
  411. for data in user_data:
  412. name = ip_pas(data[0], 2) + ' (' + data[1] + ')'
  413. div += '<li>' + str(i) + '. ' + name + '</li>'
  414. i += 1
  415. div += '</ul>'
  416. return(
  417. html_minify(
  418. template('index',
  419. imp = ['관리자 목록', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  420. data = div,
  421. menu = [['other', '기타']]
  422. )
  423. )
  424. )
  425. @route('/record/<name:path>')
  426. @route('/record/<name:path>/n/<num:int>')
  427. @route('/recent_changes')
  428. def recent_changes(name = None, num = 1):
  429. ydmin = admin_check(1, None)
  430. zdmin = admin_check(6, None)
  431. ban = ''
  432. send = '<br>'
  433. div = '<table style="width: 100%; text-align: center;"> \
  434. <tbody> \
  435. <tr> \
  436. <td style="width: 33.3%;">문서명</td> \
  437. <td style="width: 33.3%;">기여자</td> \
  438. <td style="width: 33.3%;">시간</td> \
  439. </tr>'
  440. if(name):
  441. if(num * 50 <= 0):
  442. v = 50
  443. else:
  444. v = num * 50
  445. i = v - 50
  446. curs.execute("select id, title, date, ip, send, leng from history where ip = ? order by date desc limit ?, ?", [name, str(i), str(v)])
  447. else:
  448. curs.execute("select id, title, date, ip, send, leng from history where not date = 'Dump' order by date desc limit 50")
  449. rows = curs.fetchall()
  450. for data in rows:
  451. send = '<br>'
  452. if(data[4]):
  453. if(not re.search("^(?: *)$", data[4])):
  454. send = data[4]
  455. title = html.escape(data[1])
  456. if(re.search("\+", data[5])):
  457. leng = '<span style="color:green;">' + data[5] + '</span>'
  458. elif(re.search("\-", data[5])):
  459. leng = '<span style="color:red;">' + data[5] + '</span>'
  460. else:
  461. leng = '<span style="color:gray;">' + data[5] + '</span>'
  462. if(ydmin == 1):
  463. curs.execute("select * from ban where block = ?", [data[3]])
  464. row = curs.fetchall()
  465. if(row):
  466. ban = ' <a href="/ban/' + url_pas(data[3]) + '">(해제)</a>'
  467. else:
  468. ban = ' <a href="/ban/' + url_pas(data[3]) + '">(차단)</a>'
  469. ip = ip_pas(data[3], None)
  470. if((int(data[0]) - 1) == 0):
  471. revert = ''
  472. else:
  473. revert = '<a href="/w/' + url_pas(data[1]) + '/r/' + str(int(data[0]) - 1) + '/diff/' + data[0] + '">(비교)</a> <a href="/revert/' + url_pas(data[1]) + '/r/' + str(int(data[0]) - 1) + '">(되돌리기)</a>'
  474. style = ''
  475. curs.execute("select * from hidhi where title = ? and re = ?", [data[1], data[0]])
  476. row = curs.fetchall()
  477. if(zdmin == 1):
  478. if(row):
  479. ip += ' (숨김)'
  480. hidden = ' <a href="/history/' + url_pas(data[1]) + '/r/' + data[0] + '/hidden">(공개)'
  481. else:
  482. hidden = ' <a href="/history/' + url_pas(data[1]) + '/r/' + data[0] + '/hidden">(숨김)'
  483. else:
  484. if(row):
  485. ip = '숨김'
  486. hidden = ''
  487. send = '숨김'
  488. ban = ''
  489. style = 'display:none;'
  490. else:
  491. hidden = ''
  492. div += '<tr style="' + style + '"> \
  493. <td> \
  494. <a href="/w/' + url_pas(data[1]) + '">' + title + '</a> (<a href="/history/' + url_pas(data[1]) + '">' + data[0] + '판</a>) ' + revert + ' (' + leng + ') \
  495. </td> \
  496. <td>' + ip + ban + hidden + '</td> \
  497. <td>' + data[2] + '</td> \
  498. </tr> \
  499. <tr> \
  500. <td colspan="3">' + send + '</td> \
  501. </tr>'
  502. else:
  503. div += '</tbody> \
  504. </table>'
  505. if(name):
  506. curs.execute("select end, why from ban where block = ?", [name])
  507. ban_it = curs.fetchall()
  508. if(ban_it):
  509. sub = '(차단)'
  510. else:
  511. sub = 0
  512. title = '사용자 기록'
  513. menu = [['other', '기타'], ['user', '사용자']]
  514. div += '<br><a href="/record/' + url_pas(name) + '/n/' + str(num - 1) + '">(이전)</a> <a href="/record/' + url_pas(name) + '/n/' + str(num + 1) + '">(이후)</a>'
  515. else:
  516. sub = 0
  517. menu = 0
  518. title = '최근 변경내역'
  519. return(
  520. html_minify(
  521. template('index',
  522. imp = [title, wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), sub, 0],
  523. data = div,
  524. menu = menu
  525. )
  526. )
  527. )
  528. @route('/history/<name:path>/r/<num:int>/hidden')
  529. def history_hidden(name = None, num = None):
  530. if(admin_check(6, 'history_hidden (' + name + '#' + str(num) + ')') == 1):
  531. curs.execute("select * from hidhi where title = ? and re = ?", [name, str(num)])
  532. exist = curs.fetchall()
  533. if(exist):
  534. curs.execute("delete from hidhi where title = ? and re = ?", [name, str(num)])
  535. else:
  536. curs.execute("insert into hidhi (title, re) values (?, ?)", [name, str(num)])
  537. conn.commit()
  538. return(redirect('/history/' + url_pas(name)))
  539. @route('/user_log')
  540. @route('/user_log/n/<num:int>')
  541. def user_log(num = 1):
  542. if(num * 50 <= 0):
  543. i = 50
  544. else:
  545. i = num * 50
  546. j = i - 50
  547. list_data = '<ul>'
  548. ydmin = admin_check(1, None)
  549. curs.execute("select id from user limit ?, ?", [str(j), str(i)])
  550. user_list = curs.fetchall()
  551. for data in user_list:
  552. if(ydmin == 1):
  553. curs.execute("select block from ban where block = ?", [data[0]])
  554. ban_exist = curs.fetchall()
  555. if(ban_exist):
  556. ban_button = ' <a href="/ban/' + url_pas(data[0]) + '">(해제)</a>'
  557. else:
  558. ban_button = ' <a href="/ban/' + url_pas(data[0]) + '">(차단)</a>'
  559. else:
  560. ban_button = ''
  561. ip = ip_pas(data[0], 2)
  562. list_data += '<li>' + str(j + 1) + '. ' + ip + ban_button + '</li>'
  563. j += 1
  564. else:
  565. list_data += '</ul><br><a href="/user_log/n/' + str(num - 1) + '">(이전)</a> <a href="/user_log/n/' + str(num + 1) + '">(이후)</a>'
  566. return(
  567. html_minify(
  568. template('index',
  569. imp = ['사용자 가입 기록', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  570. data = list_data,
  571. menu = [['other', '기타']]
  572. )
  573. )
  574. )
  575. @route('/admin_log')
  576. @route('/admin_log/n/<num:int>')
  577. def user_log(num = 1):
  578. if(num * 50 <= 0):
  579. i = 50
  580. else:
  581. i = num * 50
  582. j = i - 50
  583. list_data = '<ul>'
  584. curs.execute("select who, what, time from re_admin order by time desc limit ?, ?", [str(j), str(i)])
  585. get_list = curs.fetchall()
  586. for data in get_list:
  587. ip = ip_pas(data[0], 2)
  588. list_data += '<li>' + str(j + 1) + '. ' + ip + ' / ' + data[1] + ' / ' + data[2] + '</li>'
  589. j += 1
  590. else:
  591. list_data += '</ul><br> \
  592. <span>주의 : 권한 사용 안하고 열람만 해도 기록되는 경우도 있습니다.</span> \
  593. <br> \
  594. <br> \
  595. <a href="/admin_log/n/' + str(num - 1) + '">(이전)</a> <a href="/admin_log/n/' + str(num + 1) + '">(이후)</a>'
  596. return(
  597. html_minify(
  598. template('index',
  599. imp = ['관리자 권한 기록', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  600. data = list_data,
  601. menu = [['other', '기타']]
  602. )
  603. )
  604. )
  605. @route('/give_log')
  606. @route('/give_log/n/<num:int>')
  607. def give_log(num = 1):
  608. if(num * 50 <= 0):
  609. i = 50
  610. else:
  611. i = num * 50
  612. j = i - 50
  613. list_data = '<ul>'
  614. back = ''
  615. curs.execute("select name, acl from alist order by name asc limit ?, ?", [str(j), str(i)])
  616. get_list = curs.fetchall()
  617. for data in get_list:
  618. if(back != data[0]):
  619. back = data[0]
  620. j += 1
  621. list_data += '<li>' + str(j) + '. ' + data[0] + ' (' + data[1] + ')</li>'
  622. else:
  623. list_data += '</ul><br><a href="/give_log/n/' + str(num - 1) + '">(이전)</a> <a href="/give_log/n/' + str(num + 1) + '">(이후)</a>'
  624. return(
  625. html_minify(
  626. template('index',
  627. imp = ['권한 목록', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  628. data = list_data,
  629. menu = [['other', '기타']]
  630. )
  631. )
  632. )
  633. @route('/indexing')
  634. def indexing():
  635. if(admin_check(None, 'indexing') == 1):
  636. curs.execute("select name from sqlite_master where type in ('table', 'view') and name not like 'sqlite_%' union all select name from sqlite_temp_master where type in ('table', 'view') order by 1;")
  637. data = curs.fetchall()
  638. for table in data:
  639. print('----- ' + table[0] + ' -----')
  640. curs.execute('select sql from sqlite_master where name = ?', [table[0]])
  641. cul = curs.fetchall()
  642. r_cul = re.findall('(?:([^ (]*) text)', str(cul[0]))
  643. for n_cul in r_cul:
  644. print(n_cul)
  645. sql = 'create index index_' + table[0] + '_' + n_cul + ' on ' + table[0] + '(' + n_cul + ')'
  646. curs.execute(sql)
  647. conn.commit()
  648. return(redirect('/'))
  649. else:
  650. return(redirect('/error/3'))
  651. @route('/xref/<name:path>')
  652. @route('/xref/<name:path>/n/<num:int>')
  653. def xref(name = None, num = 1):
  654. if(num * 50 <= 0):
  655. v = 50
  656. else:
  657. v = num * 50
  658. i = v - 50
  659. div = '<ul>'
  660. curs.execute("delete from back where title = ? and link = ''", [name])
  661. conn.commit()
  662. curs.execute("select link, type from back where title = ? order by link asc limit ?, ?", [name, str(i), str(v)])
  663. rows = curs.fetchall()
  664. for data in rows:
  665. div += '<li><a href="/w/' + url_pas(data[0]) + '">' + data[0] + '</a>'
  666. if(data[1]):
  667. div += ' (' + data[1] + ')'
  668. div += '</li>'
  669. else:
  670. div += '</ul><br><a href="/xref/' + url_pas(name) + '/n/' + str(num - 1) + '">(이전)</a> <a href="/xref/' + url_pas(name) + '/n/' + str(num + 1) + '">(이후)</a>'
  671. return(
  672. html_minify(
  673. template('index',
  674. imp = [name, wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), ' (역링크)', 0],
  675. data = div,
  676. menu = [['w/' + url_pas(name), '문서']]
  677. )
  678. )
  679. )
  680. @route('/recent_discuss')
  681. @route('/recent_discuss/<tools:path>')
  682. def recent_discuss(tools = 'normal'):
  683. if(tools == 'normal' or tools == 'close'):
  684. div = ''
  685. if(tools == 'normal'):
  686. div += '<a href="/recent_discuss/close">(닫힌 토론)</a>'
  687. m_sub = 0
  688. else:
  689. div += '<a href="/recent_discuss">(열린 토론)</a>'
  690. m_sub = ' (닫힘)'
  691. div += '<br> \
  692. <br> \
  693. <table style="width: 100%; text-align: center;"> \
  694. <tbody> \
  695. <tr> \
  696. <td style="width: 50%;">토론명</td> \
  697. <td style="width: 50%;">시간</td> \
  698. </tr>'
  699. else:
  700. return(redirect('/'))
  701. curs.execute("select title, sub, date from rd order by date desc limit 50")
  702. rows = curs.fetchall()
  703. for data in rows:
  704. title = html.escape(data[0])
  705. sub = html.escape(data[1])
  706. close = 0
  707. if(tools == 'normal'):
  708. curs.execute("select title from stop where title = ? and sub = ? and close = 'O'", [data[0], data[1]])
  709. if(curs.fetchall()):
  710. close = 1
  711. else:
  712. curs.execute("select title from stop where title = ? and sub = ? and close = 'O'", [data[0], data[1]])
  713. if(not curs.fetchall()):
  714. close = 1
  715. if(close == 0):
  716. div += '<tr> \
  717. <td> \
  718. <a href="/topic/' + url_pas(data[0]) + '/sub/' + url_pas(data[1]) + '">' + title + '</a> (' + sub + ') \
  719. </td> \
  720. <td>' + data[2] + '</td> \
  721. </tr>'
  722. else:
  723. div += '</tbody> \
  724. </table>'
  725. return(
  726. html_minify(
  727. template('index',
  728. imp = ['최근 토론내역', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), m_sub, 0],
  729. data = div,
  730. menu = 0
  731. )
  732. )
  733. )
  734. @route('/block_log')
  735. @route('/block_log/n/<num:int>')
  736. def block_log(num = 1):
  737. if(num * 50 <= 0):
  738. v = 50
  739. else:
  740. v = num * 50
  741. i = v - 50
  742. div = '<table style="width: 100%; text-align: center;"> \
  743. <tbody> \
  744. <tr> \
  745. <td style="width: 33.3%;">차단자</td> \
  746. <td style="width: 33.3%;">관리자</td> \
  747. <td style="width: 33.3%;">기간</td> \
  748. </tr> \
  749. <tr> \
  750. <td colspan="2">이유</td> \
  751. <td>시간</td> \
  752. </tr>'
  753. curs.execute("select why, block, blocker, end, today from rb order by today desc limit ?, ?", [str(i), str(v)])
  754. rows = curs.fetchall()
  755. for data in rows:
  756. why = html.escape(data[0])
  757. b = re.search("^([0-9]{1,3}\.[0-9]{1,3})$", data[1])
  758. if(b):
  759. ip = data[1] + ' (대역)'
  760. else:
  761. ip = ip_pas(data[1], 2)
  762. if(data[3] != ''):
  763. end = data[3]
  764. else:
  765. end = '무기한'
  766. div += '<tr> \
  767. <td>' + ip + '</td> \
  768. <td>' + ip_pas(data[2], 2) + '</td> \
  769. <td>' + end + '</td> \
  770. </tr> \
  771. <tr> \
  772. <td colspan="2">' + why + '</td> \
  773. <td>' + data[4] + '</td> \
  774. </tr>'
  775. else:
  776. div += '</tbody> \
  777. </table> \
  778. <br> \
  779. <a href="/block_log/n/' + str(num - 1) + '">(이전)</a> <a href="/block_log/n/' + str(num + 1) + '">(이후)</a>'
  780. return(
  781. html_minify(
  782. template('index',
  783. imp = ['차단 기록', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  784. data = div,
  785. menu = [['other', '기타']]
  786. )
  787. )
  788. )
  789. @route('/history/<name:path>', method=['POST', 'GET'])
  790. @route('/history/<name:path>/n/<num:int>', method=['POST', 'GET'])
  791. def history_view(name = None, num = 1):
  792. if(request.method == 'POST'):
  793. return(redirect('/w/' + url_pas(name) + '/r/' + request.forms.b + '/diff/' + request.forms.a))
  794. else:
  795. select = ''
  796. if(num * 50 <= 0):
  797. i = 50
  798. else:
  799. i = num * 50
  800. j = i - 50
  801. admin1 = admin_check(1, None)
  802. admin2 = admin_check(6, None)
  803. div = '<table style="width: 100%; text-align: center;"> \
  804. <tbody> \
  805. <tr> \
  806. <td style="width: 33.3%;">판</td> \
  807. <td style="width: 33.3%;">기여자</td> \
  808. <td style="width: 33.3%;">시간</td> \
  809. </tr>'
  810. curs.execute("select send, leng, ip, date, title, id from history where title = ? order by id + 0 desc limit ?, ?", [name, str(j), str(i)])
  811. all_data = curs.fetchall()
  812. for data in all_data:
  813. select += '<option value="' + data[5] + '">' + data[5] + '</option>'
  814. if(data[0]):
  815. send = data[0]
  816. else:
  817. send = '<br>'
  818. if(re.search("^\+", data[1])):
  819. leng = '<span style="color:green;">' + data[1] + '</span>'
  820. elif(re.search("^\-", data[1])):
  821. leng = '<span style="color:red;">' + data[1] + '</span>'
  822. else:
  823. leng = '<span style="color:gray;">' + data[1] + '</span>'
  824. ip = ip_pas(data[2], None)
  825. curs.execute("select block from ban where block = ?", [data[2]])
  826. ban_it = curs.fetchall()
  827. if(ban_it):
  828. if(admin1 == 1):
  829. ban = ' <a href="/ban/' + url_pas(data[2]) + '">(해제)</a>'
  830. else:
  831. ban = ' (X)'
  832. else:
  833. if(admin1 == 1):
  834. ban = ' <a href="/ban/' + url_pas(data[2]) + '">(차단)</a>'
  835. else:
  836. ban = ''
  837. curs.execute("select * from hidhi where title = ? and re = ?", [name, data[5]])
  838. hid_it = curs.fetchall()
  839. if(hid_it):
  840. if(admin2):
  841. hidden = ' <a href="/history/' + url_pas(name) + '/r/' + url_pas(data[5]) + '/hidden">(공개)'
  842. hid = 0
  843. else:
  844. hid = 1
  845. else:
  846. if(admin2):
  847. hidden = ' <a href="/history/' + url_pas(name) + '/r/' + url_pas(data[5]) + '/hidden">(숨김)'
  848. hid = 0
  849. else:
  850. hidden = ''
  851. hid = 0
  852. if(hid == 1):
  853. div += '<tr> \
  854. <td colspan="3">숨김</td> \
  855. </tr>'
  856. else:
  857. div += '<tr> \
  858. <td> \
  859. ' + data[5] + '판</a> <a href="/w/' + url_pas(name) + '/r/' + url_pas(data[5]) + '">(보기)</a> \
  860. <a href="/raw/' + url_pas(name) + '/r/' + url_pas(data[5]) + '">(원본)</a> \
  861. <a href="/revert/' + url_pas(name) + '/r/' + url_pas(data[5]) + '">(되돌리기)</a> (' + leng + ') \
  862. </td> \
  863. <td>' + ip + ban + hidden + '</td> \
  864. <td>' + data[3] + '</td> \
  865. </tr> \
  866. <tr> \
  867. <td colspan="3">' + send + '</td> \
  868. </tr>'
  869. else:
  870. div += '</tbody> \
  871. </table> \
  872. <br> \
  873. <a href="/history/' + url_pas(name) + '/n/' + str(num - 1) + '">(이전)</a> <a href="/history/' + url_pas(name) + '/n/' + str(num + 1) + '">(이후)</a>'
  874. div = '<form method="post"> \
  875. <select name="a"> \
  876. ' + select + ' \
  877. </select> \
  878. <select name="b"> \
  879. ' + select + ' \
  880. </select> \
  881. <button class="btn btn-primary" type="submit">비교</button> \
  882. </form>' + div
  883. return(
  884. html_minify(
  885. template('index',
  886. imp = [name, wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), ' (역사)', 0],
  887. data = div,
  888. menu = [['w/' + url_pas(name), '문서']]
  889. )
  890. )
  891. )
  892. @route('/search', method=['POST'])
  893. def search():
  894. return(redirect('/search/' + url_pas(request.forms.search)))
  895. @route('/goto', method=['POST'])
  896. def goto():
  897. curs.execute("select title from data where title = ?", [request.forms.search])
  898. data = curs.fetchall()
  899. if(data):
  900. return(redirect('/w/' + url_pas(request.forms.search)))
  901. else:
  902. return(redirect('/search/' + url_pas(request.forms.search)))
  903. @route('/search/<name:path>')
  904. @route('/search/<name:path>/n/<num:int>')
  905. def deep_search(name = None, num = 1):
  906. if(num * 50 <= 0):
  907. v = num * 50
  908. else:
  909. v = 50
  910. i = v - 50
  911. div = '<ul>'
  912. div_plus = ''
  913. end = ''
  914. curs.execute("select title from data where title like ?", ['%' + name + '%'])
  915. title_list = curs.fetchall()
  916. curs.execute("select title from data where data like ?", ['%' + name + '%'])
  917. data_list = curs.fetchall()
  918. curs.execute("select title from data where title = ?", [name])
  919. exist = curs.fetchall()
  920. if(exist):
  921. div = '<ul><li>문서로 <a href="/w/' + url_pas(name) + '">바로가기</a></li><br><br>'
  922. else:
  923. div = '<ul><li>문서가 없습니다. <a class="not_thing" href="/w/' + url_pas(name) + '">바로가기</a></li><br><br>'
  924. if(title_list):
  925. no = 0
  926. if(data_list):
  927. all_list = title_list + data_list
  928. else:
  929. all_list = title_list
  930. else:
  931. if(data_list):
  932. no = 1
  933. all_list = data_list
  934. else:
  935. all_list = ''
  936. if(all_list != ''):
  937. for data in all_list:
  938. try:
  939. var_re = re.search(name, data[0])
  940. except:
  941. var_re = re.search('\\' + name, data[0])
  942. if(var_re):
  943. if(no == 0):
  944. div += '<li><a href="/w/' + url_pas(data[0]) + '">' + data[0] + '</a> (제목)</li>'
  945. else:
  946. div_plus += '<li><a href="/w/' + url_pas(data[0]) + '">' + data[0] + '</a> (내용)</li>'
  947. else:
  948. no = 1
  949. div_plus += '<li><a href="/w/' + url_pas(data[0]) + '">' + data[0] + '</a> (내용)</li>'
  950. else:
  951. div += '<li>검색 결과 없음</li>'
  952. div += div_plus + end
  953. div += '</ul><br><a href="/search/' + url_pas(name) + '/n/' + str(num - 1) + '">(이전)</a> <a href="/search/' + url_pas(name) + '/n/' + str(num + 1) + '">(이후)</a>'
  954. return(
  955. html_minify(
  956. template('index',
  957. imp = [name, wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), ' (검색)', 0],
  958. data = div,
  959. menu = 0
  960. )
  961. )
  962. )
  963. @route('/raw/<name:path>')
  964. @route('/raw/<name:path>/r/<num:int>')
  965. @route('/topic/<name:path>/sub/<sub_t:path>/raw/<num:int>')
  966. def raw_view(name = None, sub_t = None, num = None):
  967. v_name = name
  968. sub = ' (원본)'
  969. if(not sub_t and num):
  970. curs.execute("select title from hidhi where title = ? and re = ?", [name, str(num)])
  971. hid = curs.fetchall()
  972. if(hid and admin_check(6, None) != 1):
  973. return(redirect('/error/3'))
  974. curs.execute("select data from history where title = ? and id = ?", [name, str(num)])
  975. sub += ' (' + str(num) + '판)'
  976. menu = [['history/' + url_pas(name), '역사']]
  977. elif(sub_t):
  978. curs.execute("select data from topic where id = ? and title = ? and sub = ? and block = ''", [str(num), name, sub_t])
  979. v_name = '토론 원본'
  980. sub = ' (' + str(num) + '번)'
  981. menu = [['topic/' + url_pas(name) + '/sub/' + url_pas(sub_t) + '#' + str(num), '토론']]
  982. else:
  983. curs.execute("select data from data where title = ?", [name])
  984. menu = [['w/' + url_pas(name), '문서']]
  985. data = curs.fetchall()
  986. if(data):
  987. p_data = html.escape(data[0][0])
  988. p_data = '<textarea readonly style="height: 80%;">' + p_data + '</textarea>'
  989. return(
  990. html_minify(
  991. template('index',
  992. imp = [v_name, wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), sub, 0],
  993. data = p_data,
  994. menu = menu
  995. )
  996. )
  997. )
  998. else:
  999. return(redirect('/w/' + url_pas(name)))
  1000. @route('/revert/<name:path>/r/<num:int>', method=['POST', 'GET'])
  1001. def revert(name = None, num = None):
  1002. ip = ip_check()
  1003. can = acl_check(name)
  1004. today = get_time()
  1005. if(request.method == 'POST'):
  1006. curs.execute("select title from hidhi where title = ? and re = ?", [name, str(num)])
  1007. hid = curs.fetchall()
  1008. if(hid and admin_check(6, None) != 1):
  1009. return(redirect('/error/3'))
  1010. if(can == 1):
  1011. return(redirect('/ban'))
  1012. else:
  1013. curs.execute("delete from back where link = ?", [name])
  1014. curs.execute("delete from cat where cat = ?", [name])
  1015. conn.commit()
  1016. curs.execute("select data from history where title = ? and id = ?", [name, str(num)])
  1017. rows = curs.fetchall()
  1018. if(rows):
  1019. curs.execute("select data from data where title = ?", [name])
  1020. row = curs.fetchall()
  1021. if(row):
  1022. leng = leng_check(len(row[0][0]), len(rows[0][0]))
  1023. curs.execute("update data set data = ? where title = ?", [rows[0][0], name])
  1024. else:
  1025. leng = '+' + str(len(rows[0][0]))
  1026. curs.execute("insert into data (title, data, acl) values (?, ?, '')", [name, rows[0][0]])
  1027. history_plus(
  1028. name,
  1029. rows[0][0],
  1030. today,
  1031. ip,
  1032. request.forms.send + ' (' + str(num) + '판)',
  1033. leng
  1034. )
  1035. namumark(name, rows[0][0], 1, 0, 0)
  1036. conn.commit()
  1037. return(redirect('/w/' + url_pas(name)))
  1038. else:
  1039. curs.execute("select title from hidhi where title = ? and re = ?", [name, str(num)])
  1040. hid = curs.fetchall()
  1041. if(hid and admin_check(6, None) != 1):
  1042. return(redirect('/error/3'))
  1043. if(can == 1):
  1044. return(redirect('/ban'))
  1045. else:
  1046. curs.execute("select title from history where title = ? and id = ?", [name, str(num)])
  1047. rows = curs.fetchall()
  1048. if(rows):
  1049. l_c = login_check()
  1050. if(l_c == 0):
  1051. plus = '<span>비 로그인 상태입니다. 비 로그인으로 작업 시 아이피가 역사에 기록됩니다.</span> \
  1052. <br> \
  1053. <br>'
  1054. else:
  1055. plus = ''
  1056. return(
  1057. html_minify(
  1058. template('index',
  1059. imp = [name, wiki_set(1), wiki_set(3), l_c, custom_css(), custom_js(), ' (되돌리기)', 0],
  1060. data = plus + ' \
  1061. <form method="post"> \
  1062. <input placeholder="사유" style="width: 100%;" class="form-control input-sm" name="send" type="text"> \
  1063. <br> \
  1064. <br> \
  1065. <button class="btn btn-primary" type="submit">되돌리기</button> \
  1066. </form>',
  1067. menu = [['history/' + url_pas(name), '역사'], ['recent_changes', '최근 변경']]
  1068. )
  1069. )
  1070. )
  1071. else:
  1072. return(redirect('/w/' + url_pas(name)))
  1073. @route('/m_del', method=['POST', 'GET'])
  1074. def m_del():
  1075. today = get_time()
  1076. ip = ip_check()
  1077. if(admin_check(2, 'm_del') == 1):
  1078. if(request.method == 'POST'):
  1079. data = request.forms.content + '\r\n'
  1080. m = re.findall('(.*)\r\n', data)
  1081. for g in m:
  1082. curs.execute("select data from data where title = ?", [g])
  1083. rows = curs.fetchall()
  1084. if(rows):
  1085. curs.execute("delete from back where title = ?", [g])
  1086. curs.execute("delete from cat where title = ?", [g])
  1087. leng = '-' + str(len(rows[0][0]))
  1088. curs.execute("delete from data where title = ?", [g])
  1089. history_plus(
  1090. g,
  1091. '',
  1092. today,
  1093. ip,
  1094. request.forms.send + ' (대량 삭제)',
  1095. leng
  1096. )
  1097. data = re.sub('(.*)\r\n', '', data, 1)
  1098. conn.commit()
  1099. return(redirect('/'))
  1100. else:
  1101. return(
  1102. html_minify(
  1103. template('index',
  1104. imp = ['많은 문서 삭제', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  1105. data = '<span> \
  1106. 문서명 A \
  1107. <br> \
  1108. 문서명 B \
  1109. <br> \
  1110. 문서명 C \
  1111. <br> \
  1112. <br> \
  1113. 이런 식으로 적으세요. \
  1114. </span> \
  1115. <br> \
  1116. <br> \
  1117. <form method="post"> \
  1118. <textarea style="height: 80%;" name="content"></textarea> \
  1119. <br> \
  1120. <br> \
  1121. <input placeholder="사유" style="width: 100%;" class="form-control input-sm" name="send" type="text"> \
  1122. <br> \
  1123. <br> \
  1124. <div class="form-actions"> \
  1125. <button class="btn btn-primary" type="submit">삭제</button> \
  1126. </div> \
  1127. </form>',
  1128. menu = [['manager', '관리자']]
  1129. )
  1130. )
  1131. )
  1132. else:
  1133. return(redirect('/error/3'))
  1134. @route('/edit/<name:path>', method=['POST', 'GET'])
  1135. @route('/edit/<name:path>/section/<num:int>', method=['POST', 'GET'])
  1136. def edit(name = None, num = None):
  1137. ip = ip_check()
  1138. can = acl_check(name)
  1139. if(request.method == 'POST'):
  1140. if(can == 1):
  1141. return(redirect('/ban'))
  1142. if(len(request.forms.send) > 500):
  1143. return(redirect('/error/15'))
  1144. if(request.forms.otent == request.forms.content):
  1145. return(redirect('/error/18'))
  1146. today = get_time()
  1147. content = savemark(request.forms.content)
  1148. curs.execute("delete from back where link = ?", [name])
  1149. curs.execute("delete from cat where cat = ?", [name])
  1150. curs.execute("select data from data where title = ?", [name])
  1151. rows = curs.fetchall()
  1152. if(rows):
  1153. leng = leng_check(len(request.forms.otent), len(content))
  1154. if(num):
  1155. content = rows[0][0].replace(request.forms.otent, content)
  1156. curs.execute("update data set data = ? where title = ?", [content, name])
  1157. else:
  1158. leng = '+' + str(len(content))
  1159. curs.execute("insert into data (title, data, acl) values (?, ?, '')", [name, content])
  1160. history_plus(
  1161. name,
  1162. content,
  1163. today,
  1164. ip,
  1165. send_p(request.forms.send),
  1166. leng
  1167. )
  1168. namumark(name, content, 1, 0, 0)
  1169. include_check(name, content)
  1170. conn.commit()
  1171. return(redirect('/w/' + url_pas(name)))
  1172. else:
  1173. if(can == 1):
  1174. return(redirect('/ban'))
  1175. curs.execute("select data from data where title = ?", [name])
  1176. rows = curs.fetchall()
  1177. if(rows):
  1178. if(num):
  1179. i = 0
  1180. j = 0
  1181. data = rows[0][0] + '\r\n'
  1182. while(1):
  1183. m = re.search("((?:={1,6})\s?(?:[^=]*)\s?(?:={1,6})(?:\s+)?\n(?:(?:(?:(?!(?:={1,6})\s?(?:[^=]*)\s?(?:={1,6})(?:\s+)?\n).)*)(?:\n)?)+)", data)
  1184. if(m):
  1185. if(i == num - 1):
  1186. g = m.groups()
  1187. data = re.sub("\r\n$", "", g[0])
  1188. break
  1189. else:
  1190. data = re.sub("((?:={1,6})\s?(?:[^=]*)\s?(?:={1,6})(?:\s+)?\n(?:(?:(?:(?!(?:={1,6})\s?(?:[^=]*)\s?(?:={1,6})(?:\s+)?\n).)*)(?:\n)?)+)", "", data, 1)
  1191. i += 1
  1192. else:
  1193. j = 1
  1194. break
  1195. if(j == 0):
  1196. data = re.sub("\r\n$", "", data)
  1197. else:
  1198. data = rows[0][0]
  1199. else:
  1200. data = ''
  1201. if(num):
  1202. action = '/section/' + str(num)
  1203. else:
  1204. action = ''
  1205. return(
  1206. html_minify(
  1207. template('index',
  1208. imp = [name, wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), ' (수정)', 0],
  1209. data = '<form method="post" action="/edit/' + url_pas(name) + action + '"> \
  1210. <textarea style="height: 80%;" name="content">' + data + '</textarea> \
  1211. <textarea style="display: none; height: 80%;" name="otent">' + data + '</textarea> \
  1212. <br> \
  1213. <br> \
  1214. <input placeholder="사유" name="send" style="width: 100%;" type="text"> \
  1215. <br> \
  1216. <br> \
  1217. <div class="form-actions"> \
  1218. <button id="save" class="btn btn-primary" type="submit">저장</button> \
  1219. <button id="preview" class="btn" type="submit" formaction="/preview/' + url_pas(name) + action + '">미리보기</button> \
  1220. </div> \
  1221. </form>',
  1222. menu = [['w/' + url_pas(name), '문서']]
  1223. )
  1224. )
  1225. )
  1226. @route('/preview/<name:path>', method=['POST'])
  1227. @route('/preview/<name:path>/section/<num:int>', method=['POST'])
  1228. def preview(name = None, num = None):
  1229. ip = ip_check()
  1230. can = acl_check(name)
  1231. if(can == 1):
  1232. return(redirect('/ban'))
  1233. newdata = request.forms.content
  1234. newdata = re.sub('^#(?:redirect|넘겨주기) (?P<in>[^\n]*)', ' * [[\g<in>]] 문서로 넘겨주기', newdata)
  1235. enddata = namumark(name, newdata, 0, 0, 0)
  1236. if(num):
  1237. action = '/section/' + str(num)
  1238. else:
  1239. action = ''
  1240. return(
  1241. html_minify(
  1242. template('index',
  1243. imp = [name, wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), ' (미리보기)', 0],
  1244. data = '<form method="post" action="/edit/' + url_pas(name) + action + '"> \
  1245. <textarea style="height: 80%;" name="content">' + request.forms.content + '</textarea> \
  1246. <textarea style="display: none; height: 80%;" name="otent">' + request.forms.otent + '</textarea> \
  1247. <br> \
  1248. <br> \
  1249. <input placeholder="사유" name="send" style="width: 100%;" type="text"> \
  1250. <br> \
  1251. <br> \
  1252. <div class="form-actions"> \
  1253. <button id="save" class="btn btn-primary" type="submit">저장</button> \
  1254. <button id="preview" class="btn" type="submit" formaction="/preview/' + url_pas(name) + action + '">미리보기</button> \
  1255. </div> \
  1256. </form> \
  1257. <br>' + enddata,
  1258. menu = [['w/' + url_pas(name), '문서']]
  1259. )
  1260. )
  1261. )
  1262. @route('/delete/<name:path>', method=['POST', 'GET'])
  1263. def delete(name = None):
  1264. ip = ip_check()
  1265. can = acl_check(name)
  1266. if(request.method == 'POST'):
  1267. curs.execute("select data from data where title = ?", [name])
  1268. rows = curs.fetchall()
  1269. if(rows):
  1270. if(can == 1):
  1271. return(redirect('/ban'))
  1272. today = get_time()
  1273. leng = '-' + str(len(rows[0][0]))
  1274. history_plus(
  1275. name,
  1276. '',
  1277. today,
  1278. ip,
  1279. request.forms.send + ' (삭제)',
  1280. leng
  1281. )
  1282. curs.execute("delete from back where link = ?", [name])
  1283. curs.execute("delete from cat where cat = ?", [name])
  1284. curs.execute("delete from data where title = ?", [name])
  1285. conn.commit()
  1286. return(redirect('/w/' + url_pas(name)))
  1287. else:
  1288. curs.execute("select title from data where title = ?", [name])
  1289. rows = curs.fetchall()
  1290. if(rows):
  1291. if(can == 1):
  1292. return(redirect('/ban'))
  1293. else:
  1294. l_c = login_check()
  1295. if(l_c == 0):
  1296. plus = '<span>비 로그인 상태입니다. 비 로그인으로 작업 시 아이피가 역사에 기록됩니다.</span><br><br>'
  1297. else:
  1298. plus = ''
  1299. return(
  1300. html_minify(
  1301. template('index',
  1302. imp = [name, wiki_set(1), wiki_set(3), l_c, custom_css(), custom_js(), ' (삭제)', 0],
  1303. data = '<form method="post"> \
  1304. ' + plus + ' \
  1305. <input placeholder="사유" style="width: 100%;" class="form-control input-sm" name="send" type="text"> \
  1306. <br> \
  1307. <br> \
  1308. <button class="btn btn-primary" type="submit">삭제</button> \
  1309. </form>',
  1310. menu = [['w/' + url_pas(name), '문서']]
  1311. )
  1312. )
  1313. )
  1314. else:
  1315. return(redirect('/w/' + url_pas(name)))
  1316. @route('/move_data/<name:path>')
  1317. @route('/move_data/<name:path>/<n:int>')
  1318. def move_data(name = None, n = 1):
  1319. if(n > 0):
  1320. i = n
  1321. else:
  1322. i = 1
  1323. j = i * 50
  1324. da = '<ul>'
  1325. curs.execute("select origin, new, date, who, send from move where origin = ? or new = ? limit ?, ?", [name, name, j - 50, j])
  1326. for d in curs.fetchall():
  1327. if(d[4] == ''):
  1328. sn = '(없음)'
  1329. else:
  1330. sn = d[4]
  1331. da += '<li><a href="/move_data/' + url_pas(d[0]) + '">' + d[0] + '</a> >> <a href="/move_data/' + url_pas(d[1]) + '">' + d[1] + '</a> / ' + d[2] + ' / ' + d[3] + ' / ' + sn + '</li>'
  1332. da += '</ul><br><a href="/move_data/' + name + '/' + str(n - 1) + '">(이전)</a> <a href="/move_data/' + name + '/' + str(n + 1) + '">(이후)</a>'
  1333. return(
  1334. html_minify(
  1335. template('index',
  1336. imp = [name, wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), ' (이동)', 0],
  1337. data = da,
  1338. menu = [['w/' + url_pas(name), '문서']]
  1339. )
  1340. )
  1341. )
  1342. @route('/move/<name:path>', method=['POST', 'GET'])
  1343. def move(name = None):
  1344. ip = ip_check()
  1345. can = acl_check(name)
  1346. today = get_time()
  1347. if(can == 1):
  1348. return(redirect('/ban'))
  1349. if(request.method == 'POST'):
  1350. curs.execute("select data from data where title = ?", [name])
  1351. rows = curs.fetchall()
  1352. leng = '0'
  1353. curs.execute("select title from history where title = ?", [request.forms.title])
  1354. row = curs.fetchall()
  1355. if(row):
  1356. return(redirect('/error/19'))
  1357. if(rows):
  1358. curs.execute("update data set title = ? where title = ?", [request.forms.title, name])
  1359. curs.execute("update back set link = ? where link = ?", [request.forms.title, name])
  1360. curs.execute("update cat set cat = ? where cat = ?", [request.forms.title, name])
  1361. d = rows[0][0]
  1362. else:
  1363. d = ''
  1364. history_plus(
  1365. name,
  1366. d,
  1367. today,
  1368. ip,
  1369. request.forms.send + ' (<a href="/w/' + url_pas(name) + '">' + name + '</a> - <a href="/w/' + url_pas(request.forms.title) + '">' + request.forms.title + '</a> 이동)',
  1370. leng
  1371. )
  1372. curs.execute('insert into move (origin, new, date, who, send) values (?, ?, ?, ?, ?)', [name, request.forms.title, today, ip, request.forms.send])
  1373. curs.execute("update history set title = ? where title = ?", [request.forms.title, name])
  1374. conn.commit()
  1375. return(redirect('/w/' + url_pas(request.forms.title)))
  1376. else:
  1377. l_c = login_check()
  1378. if(l_c == 0):
  1379. plus = '<span>비 로그인 상태입니다. 비 로그인으로 작업 시 아이피가 역사에 기록됩니다.</span><br><br>'
  1380. else:
  1381. plus = ''
  1382. return(
  1383. html_minify(
  1384. template('index',
  1385. imp = [name, wiki_set(1), wiki_set(3), l_c, custom_css(), custom_js(), ' (이동)', 0],
  1386. data = '<form method="post"> \
  1387. ' + plus + ' \
  1388. <input placeholder="문서명" class="form-control input-sm" value="' + name + '" name="title" type="text"> \
  1389. <br> \
  1390. <br> \
  1391. <input placeholder="사유" style="width: 100%;" class="form-control input-sm" name="send" type="text"> \
  1392. <br> \
  1393. <br> \
  1394. <button class="btn btn-primary" type="submit">이동</button> \
  1395. </form>',
  1396. menu = [['w/' + url_pas(name), '문서'], ['move_data/' + url_pas(name), '기록']]
  1397. )
  1398. )
  1399. )
  1400. @route('/other')
  1401. def other():
  1402. return(
  1403. html_minify(
  1404. template('index',
  1405. imp = ['기타 메뉴', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  1406. data = namumark('', '[목차(없음)]\r\n' + \
  1407. '== 기록 ==\r\n' + \
  1408. ' * [[wiki:block_log|차단 기록]]\r\n' + \
  1409. ' * [[wiki:user_log|가입 기록]]\r\n' + \
  1410. ' * [[wiki:admin_log|권한 기록]]\r\n' + \
  1411. ' * [[wiki:manager/6|기여 기록]]\r\n' + \
  1412. ' * [[wiki:manager/7|토론 기록]]\r\n' + \
  1413. ' * [[wiki:not_close_topic|열린 토론 목록]]\r\n' + \
  1414. '== 기타 ==\r\n' + \
  1415. ' * [[wiki:title_index|모든 문서]]\r\n' + \
  1416. ' * [[wiki:acl_list|ACL 문서]]\r\n' + \
  1417. ' * [[wiki:admin_list|관리자 목록]]\r\n' + \
  1418. ' * [[wiki:give_log|권한 목록]]\r\n' + \
  1419. ' * [[wiki:upload|파일 올리기]]\r\n' + \
  1420. '== 관리자 ==\r\n' + \
  1421. ' * [[wiki:manager/1|관리자 메뉴]]\r\n' + \
  1422. '== 버전 ==\r\n' + \
  1423. '이 오픈나무는 [[https://github.com/2DU/openNAMU/blob/SQLite/version.md|' + r_ver + p_ver + ']]판 입니다.', 0, 0, 0),
  1424. menu = 0
  1425. )
  1426. )
  1427. )
  1428. @route('/manager', method=['POST', 'GET'])
  1429. @route('/manager/<num:int>', method=['POST', 'GET'])
  1430. def manager(num = 1):
  1431. if(num == 1):
  1432. return(
  1433. html_minify(
  1434. template('index',
  1435. imp = ['관리자 메뉴', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  1436. data = namumark('', '[목차(없음)]\r\n' + \
  1437. '== 목록 ==\r\n' + \
  1438. ' * [[wiki:manager/2|문서 ACL]]\r\n' + \
  1439. ' * [[wiki:manager/3|사용자 검사]]\r\n' + \
  1440. ' * [[wiki:manager/10|사용자 비교]]\r\n' + \
  1441. ' * [[wiki:manager/4|사용자 차단]]\r\n' + \
  1442. ' * [[wiki:manager/5|권한 주기]]\r\n' + \
  1443. ' * [[wiki:m_del|여러 문서 삭제]]\r\n' + \
  1444. '== 소유자 ==\r\n' + \
  1445. ' * [[wiki:indexing|인덱싱]]\r\n' + \
  1446. ' * [[wiki:manager/8|관리 그룹 생성]]\r\n' + \
  1447. ' * [[wiki:edit_set|설정 편집]]\r\n' + \
  1448. ' * [[wiki:manager/9|JSON 출력]]\r\n' + \
  1449. ' * [[wiki:json_in|JSON 입력]]\r\n' + \
  1450. '== 기타 ==\r\n' + \
  1451. ' * 이 메뉴에 없는 기능은 해당 문서의 역사나 토론에서 바로 사용 가능함', 0, 0, 0),
  1452. menu = [['other', '기타']]
  1453. )
  1454. )
  1455. )
  1456. elif(num == 2):
  1457. if(request.method == 'POST'):
  1458. return(redirect('/acl/' + url_pas(request.forms.name)))
  1459. else:
  1460. return(
  1461. html_minify(
  1462. template('index',
  1463. imp = ['ACL 이동', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  1464. data = '<form method="post"> \
  1465. <input placeholder="문서명" name="name" type="text"> \
  1466. <br> \
  1467. <br> \
  1468. <button class="btn btn-primary" type="submit">이동</button> \
  1469. </form>',
  1470. menu = [['manager', '관리자']]
  1471. )
  1472. )
  1473. )
  1474. elif(num == 3):
  1475. if(request.method == 'POST'):
  1476. return(redirect('/check/' + url_pas(request.forms.name)))
  1477. else:
  1478. return(
  1479. html_minify(
  1480. template('index',
  1481. imp = ['검사 이동', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  1482. data = '<form method="post"> \
  1483. <input placeholder="사용자명" name="name" type="text"> \
  1484. <br> \
  1485. <br> \
  1486. <button class="btn btn-primary" type="submit">이동</button> \
  1487. </form>',
  1488. menu = [['manager', '관리자']]
  1489. )
  1490. )
  1491. )
  1492. elif(num == 4):
  1493. if(request.method == 'POST'):
  1494. return(redirect('/ban/' + url_pas(request.forms.name)))
  1495. else:
  1496. return(
  1497. html_minify(
  1498. template('index',
  1499. imp = ['차단 이동', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  1500. data = '<form method="post"> \
  1501. <input placeholder="사용자명" name="name" type="text"> \
  1502. <br> \
  1503. <br> \
  1504. <button class="btn btn-primary" type="submit">이동</button> \
  1505. </form>',
  1506. menu = [['manager', '관리자']]
  1507. )
  1508. )
  1509. )
  1510. elif(num == 5):
  1511. if(request.method == 'POST'):
  1512. return(redirect('/admin/' + url_pas(request.forms.name)))
  1513. else:
  1514. return(
  1515. html_minify(
  1516. template('index',
  1517. imp = ['권한 이동', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  1518. data = '<form method="post"> \
  1519. <input placeholder="사용자명" name="name" type="text"> \
  1520. <br> \
  1521. <br> \
  1522. <button class="btn btn-primary" type="submit">이동</button> \
  1523. </form>',
  1524. menu = [['manager', '관리자']]
  1525. )
  1526. )
  1527. )
  1528. elif(num == 6):
  1529. if(request.method == 'POST'):
  1530. return(redirect('/record/' + url_pas(request.forms.name)))
  1531. else:
  1532. return(
  1533. html_minify(
  1534. template('index',
  1535. imp = ['기록 이동', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  1536. data = '<form method="post"> \
  1537. <input placeholder="사용자명" name="name" type="text"> \
  1538. <br> \
  1539. <br> \
  1540. <button class="btn btn-primary" type="submit">이동</button> \
  1541. </form>',
  1542. menu = [['other', '기타']]
  1543. )
  1544. )
  1545. )
  1546. elif(num == 7):
  1547. if(request.method == 'POST'):
  1548. return(redirect('/user/' + url_pas(request.forms.name) + '/topic'))
  1549. else:
  1550. return(
  1551. html_minify(
  1552. template('index',
  1553. imp = ['토론 기록 이동', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  1554. data = '<form method="post"> \
  1555. <input placeholder="사용자명" name="name" type="text"> \
  1556. <br> \
  1557. <br> \
  1558. <button class="btn btn-primary" type="submit">이동</button> \
  1559. </form>',
  1560. menu = [['other', '기타']]
  1561. )
  1562. )
  1563. )
  1564. elif(num == 8):
  1565. if(request.method == 'POST'):
  1566. return(redirect('/admin_plus/' + url_pas(request.forms.name)))
  1567. else:
  1568. return(
  1569. html_minify(
  1570. template('index',
  1571. imp = ['그룹 생성 이동', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  1572. data = '<form method="post"> \
  1573. <input placeholder="그룹명" name="name" type="text"> \
  1574. <br> \
  1575. <br> \
  1576. <button class="btn btn-primary" type="submit">이동</button> \
  1577. </form>',
  1578. menu = [['manager', '관리자']]
  1579. )
  1580. )
  1581. )
  1582. elif(num == 9):
  1583. if(request.method == 'POST'):
  1584. return(redirect('/json_out/' + url_pas(request.forms.name)))
  1585. else:
  1586. return(
  1587. html_minify(
  1588. template('index',
  1589. imp = ['문서 출력 이동', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  1590. data = '<form method="post"> \
  1591. <input placeholder="문서명" name="name" type="text"> \
  1592. <br> \
  1593. <br> \
  1594. <button class="btn btn-primary" type="submit">이동</button> \
  1595. </form>',
  1596. menu = [['manager', '관리자']]
  1597. )
  1598. )
  1599. )
  1600. elif(num == 10):
  1601. if(request.method == 'POST'):
  1602. return(redirect('/check/' + url_pas(request.forms.name) + '/' + url_pas(request.forms.name2)))
  1603. else:
  1604. return(
  1605. html_minify(
  1606. template('index',
  1607. imp = ['검사 이동', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  1608. data = '<form method="post"> \
  1609. <input placeholder="사용자명" name="name" type="text"> \
  1610. <br> \
  1611. <br> \
  1612. <input placeholder="비교 대상" name="name2" type="text"> \
  1613. <br> \
  1614. <br> \
  1615. <button class="btn btn-primary" type="submit">이동</button> \
  1616. </form>',
  1617. menu = [['manager', '관리자']]
  1618. )
  1619. )
  1620. )
  1621. else:
  1622. return(redirect('/'))
  1623. @route('/json_out/<name:path>')
  1624. def json_out(name = None):
  1625. if(admin_check(None, 'json_out') == 1):
  1626. curs.execute('select data from data where title = ?', [name])
  1627. get_d = curs.fetchall()
  1628. if(get_d):
  1629. da = get_d[0][0]
  1630. else:
  1631. da = ''
  1632. curs.execute('select ip from history where title = ? order by ip asc', [name])
  1633. get_h = curs.fetchall()
  1634. var_n = ''
  1635. hi_d = ''
  1636. for hi in get_h:
  1637. if(hi[0] != var_n):
  1638. var_n = hi[0]
  1639. hi_d += json.dumps(hi[0]) + ', '
  1640. else:
  1641. hi_d = re.sub(', $', '', hi_d)
  1642. if(hi_d == ''):
  1643. return(redirect('/w/' + url_pas(name)))
  1644. json_f = '{ "title" : ' + json.dumps(name) + ', "data" : ' + json.dumps(da) + ', "history" : [' + hi_d + '] }'
  1645. return(json_f)
  1646. else:
  1647. return(redirect('/error/3'))
  1648. @route('/json_in', method=['POST', 'GET'])
  1649. def json_in():
  1650. if(admin_check(None, 'json_in') == 1):
  1651. if(request.method == 'POST'):
  1652. data = json.loads(request.forms.data)
  1653. title = data["title"]
  1654. curs.execute('select title from history where title = ?', [title])
  1655. get_d = curs.fetchall()
  1656. if(get_d):
  1657. return(redirect('/w/' + url_pas(title)))
  1658. curs.execute('insert into data (title, data, acl) values (?, ?, "")', [title, data["data"]])
  1659. i = 0
  1660. date = get_time()
  1661. for hi in data["history"]:
  1662. i += 1
  1663. if(i == 1):
  1664. curs.execute('insert into history (id, title, data, date, ip, send, leng) values (?, ?, ?, ?, ?, "", ?)', [i, title, data["data"], date, hi, '+' + len(data["data"])])
  1665. else:
  1666. curs.execute('insert into history (id, title, data, date, ip, send, leng) values (?, ?, "", ?, ?, "", "0")', [i, title, date, hi])
  1667. conn.commit()
  1668. return(redirect('/w/' + url_pas(title)))
  1669. else:
  1670. return(
  1671. html_minify(
  1672. template('index',
  1673. imp = ['문서 JSON 입력', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  1674. data = '<form method="post"> \
  1675. <textarea style="height: 80%;" name="data"></textarea> \
  1676. <br> \
  1677. <br> \
  1678. <button class="btn btn-primary" type="submit">입력</button> \
  1679. </form>',
  1680. menu = [['manager', '관리자']]
  1681. )
  1682. )
  1683. )
  1684. else:
  1685. return(redirect('/error/3'))
  1686. @route('/title_index')
  1687. @route('/title_index/<num:int>/<page:int>')
  1688. def title_index(num = 1000, page = 1):
  1689. if(page > 0):
  1690. v_page = page * num
  1691. else:
  1692. v_page = 1 * num
  1693. if(num != 0):
  1694. i = [v_page - num + 1]
  1695. else:
  1696. i = [1, 0, 0, 0, 0, 0]
  1697. data = '<ul><a href="/title_index/0/1">(전체)</a> <a href="/title_index/500/1">(500)</a> <a href="/title_index/5000/1">(5000개)</a> <a href="/title_index/10000/1">(10000개)</a> <a href="/title_index/50000/1">(50000개)</a><br><br>'
  1698. if(num == 0):
  1699. curs.execute("select title from data order by title asc")
  1700. else:
  1701. curs.execute("select title from data order by title asc limit ?, ?", [str(v_page - num), str(num)])
  1702. title_list = curs.fetchall()
  1703. for list_data in title_list:
  1704. data += '<li>' + str(i[0]) + '. <a href="/w/' + url_pas(list_data[0]) + '">' + list_data[0] + '</a></li>'
  1705. if(num == 0):
  1706. if(re.search('^분류:', list_data[0])):
  1707. i[1] += 1
  1708. elif(re.search('^사용자:', list_data[0])):
  1709. i[2] += 1
  1710. elif(re.search('^틀:', list_data[0])):
  1711. i[3] += 1
  1712. elif(re.search('^파일:', list_data[0])):
  1713. i[4] += 1
  1714. else:
  1715. i[5] += 1
  1716. i[0] += 1
  1717. if(num == 0):
  1718. if(title_list):
  1719. data += '<br><br><li>이 위키에는 총 ' + str(i[0]) + '개의 문서가 있습니다.</li><br><br> \
  1720. <li>틀 문서는 총 ' + str(i[3]) + '개의 문서가 있습니다.</li> \
  1721. <li>분류 문서는 총 ' + str(i[1]) + '개의 문서가 있습니다.</li> \
  1722. <li>사용자 문서는 총 ' + str(i[2]) + '개의 문서가 있습니다.</li> \
  1723. <li>파일 문서는 총 ' + str(i[4]) + '개의 문서가 있습니다.</li> \
  1724. <li>나머지 문서는 총 ' + str(i[5]) + '개의 문서가 있습니다.</li>'
  1725. else:
  1726. data += '</ul><br><a href="/title_index/' + str(num) + '/' + str(page - 1) + '">(이전)</a> <a href="/title_index/' + str(num) + '/' + str(page + 1) + '">(이후)</a>'
  1727. return(
  1728. html_minify(
  1729. template('index',
  1730. imp = ['모든 문서', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), ' (' + str(num) + ')', 0],
  1731. data = data,
  1732. menu = [['other', '기타']]
  1733. )
  1734. )
  1735. )
  1736. @route('/topic/<name:path>/sub/<sub:path>/b/<num:int>')
  1737. def topic_block(name = None, sub = None, num = None):
  1738. if(admin_check(3, 'blind (' + name + ' - ' + sub + '#' + str(num) + ')') == 1):
  1739. curs.execute("select block from topic where title = ? and sub = ? and id = ?", [name, sub, str(num)])
  1740. block = curs.fetchall()
  1741. if(block):
  1742. if(block[0][0] == 'O'):
  1743. curs.execute("update topic set block = '' where title = ? and sub = ? and id = ?", [name, sub, str(num)])
  1744. else:
  1745. curs.execute("update topic set block = 'O' where title = ? and sub = ? and id = ?", [name, sub, str(num)])
  1746. conn.commit()
  1747. rd_plus(
  1748. name,
  1749. sub,
  1750. get_time()
  1751. )
  1752. return(redirect('/topic/' + url_pas(name) + '/sub/' + url_pas(sub)))
  1753. else:
  1754. return(redirect('/error/3'))
  1755. @route('/topic/<name:path>/sub/<sub:path>/notice/<num:int>')
  1756. def topic_top(name = None, sub = None, num = None):
  1757. if(admin_check(3, 'notice (' + name + ' - ' + sub + '#' + str(num) + ')') == 1):
  1758. curs.execute("select * from topic where title = ? and sub = ? and id = ?", [name, sub, str(num)])
  1759. topic_data = curs.fetchall()
  1760. if(topic_data):
  1761. curs.execute("select top from topic where id = ? and title = ? and sub = ?", [str(num), name, sub])
  1762. top_data = curs.fetchall()
  1763. if(top_data):
  1764. if(top_data[0][0] == 'O'):
  1765. curs.execute("update topic set top = '' where title = ? and sub = ? and id = ?", [name, sub, str(num)])
  1766. else:
  1767. curs.execute("update topic set top = 'O' where title = ? and sub = ? and id = ?", [name, sub, str(num)])
  1768. conn.commit()
  1769. rd_plus(
  1770. name,
  1771. sub,
  1772. get_time()
  1773. )
  1774. return(redirect('/topic/' + url_pas(name) + '/sub/' + url_pas(sub)))
  1775. else:
  1776. return(redirect('/error/3'))
  1777. @route('/topic/<name:path>/sub/<sub:path>/tool/agree')
  1778. def topic_agree(name = None, sub = None):
  1779. if(admin_check(3, 'agree (' + name + ' - ' + sub + ')') == 1):
  1780. ip = ip_check()
  1781. curs.execute("select id from topic where title = ? and sub = ? order by id + 0 desc limit 1", [name, sub])
  1782. topic_check = curs.fetchall()
  1783. if(topic_check):
  1784. time = get_time()
  1785. curs.execute("select title from agreedis where title = ? and sub = ?", [name, sub])
  1786. agree = curs.fetchall()
  1787. if(agree):
  1788. curs.execute("insert into topic (id, title, sub, data, date, ip, block, top) values (?, ?, ?, '합의 결렬', ?, ?, '', '1')", [str(int(topic_check[0][0]) + 1), name, sub, time, ip])
  1789. curs.execute("delete from agreedis where title = ? and sub = ?", [name, sub])
  1790. else:
  1791. curs.execute("insert into topic (id, title, sub, data, date, ip, block, top) values (?, ?, ?, '합의 완료', ?, ?, '', '1')", [str(int(topic_check[0][0]) + 1), name, sub, time, ip])
  1792. curs.execute("insert into agreedis (title, sub) values (?, ?)", [name, sub])
  1793. conn.commit()
  1794. rd_plus(
  1795. name,
  1796. sub,
  1797. time
  1798. )
  1799. return(redirect('/topic/' + url_pas(name) + '/sub/' + url_pas(sub)))
  1800. else:
  1801. return(redirect('/error/3'))
  1802. @route('/topic/<name:path>/sub/<sub:path>/tool/<tool:path>')
  1803. def topic_stop(name = None, sub = None, tool = None):
  1804. if(tool == 'close'):
  1805. close = 'O'
  1806. n_close = ''
  1807. data = '토론 닫음'
  1808. n_data = '토론 다시 열기'
  1809. elif(tool == 'stop'):
  1810. close = ''
  1811. n_close = 'O'
  1812. data = '토론 정지'
  1813. n_data = '토론 재 시작'
  1814. else:
  1815. return(redirect('/topic/' + url_pas(name) + '/sub/' + url_pas(sub)))
  1816. if(admin_check(3, 'topic stop and end (' + name + ' - ' + sub + ')') == 1):
  1817. ip = ip_check()
  1818. curs.execute("select id from topic where title = ? and sub = ? order by id + 0 desc limit 1", [name, sub])
  1819. topic_check = curs.fetchall()
  1820. if(topic_check):
  1821. time = get_time()
  1822. curs.execute("select title from stop where title = ? and sub = ? and close = ?", [name, sub, close])
  1823. stop = curs.fetchall()
  1824. if(stop):
  1825. curs.execute("insert into topic (id, title, sub, data, date, ip, block, top) values (?, ?, ?, ?, ?, ?, '', '1')", [str(int(topic_check[0][0]) + 1), name, sub, n_data, time, ip])
  1826. curs.execute("delete from stop where title = ? and sub = ? and close = ?", [name, sub, close])
  1827. else:
  1828. curs.execute("insert into topic (id, title, sub, data, date, ip, block, top) values (?, ?, ?, ?, ?, ?, '', '1')", [str(int(topic_check[0][0]) + 1), name, sub, data, time, ip])
  1829. curs.execute("insert into stop (title, sub, close) values (?, ?, ?)", [name, sub, close])
  1830. curs.execute("delete from stop where title = ? and sub = ? and close = ?", [name, sub, n_close])
  1831. conn.commit()
  1832. rd_plus(
  1833. name,
  1834. sub,
  1835. time
  1836. )
  1837. return(redirect('/topic/' + url_pas(name) + '/sub/' + url_pas(sub)))
  1838. else:
  1839. return(redirect('/error/3'))
  1840. @route('/topic/<name:path>/sub/<sub:path>', method=['POST', 'GET'])
  1841. def topic(name = None, sub = None):
  1842. ip = ip_check()
  1843. ban = topic_check(name, sub)
  1844. admin = admin_check(3, None)
  1845. if(request.method == 'POST'):
  1846. today = get_time()
  1847. curs.execute("select id from topic where title = ? and sub = ? order by id + 0 desc limit 1", [name, sub])
  1848. rows = curs.fetchall()
  1849. if(rows):
  1850. num = int(rows[0][0]) + 1
  1851. else:
  1852. num = 1
  1853. m = re.search('^사용자:([^/]+)', name)
  1854. if(m):
  1855. d = m.groups()
  1856. curs.execute('insert into alarm (name, data, date) values (?, ?, ?)', [d[0], ip + '님이 <a href="/topic/' + url_pas(name) + '/sub/' + url_pas(sub) + '">사용자 토론</a>을 시작했습니다.', today])
  1857. if(ban == 1 and admin != 1):
  1858. return(redirect('/ban'))
  1859. rd_plus(
  1860. name,
  1861. sub,
  1862. today
  1863. )
  1864. data = re.sub("\[\[(분류:(?:(?:(?!\]\]).)*))\]\]", "[br]", request.forms.content)
  1865. m = re.findall("(?:#([0-9]+))", data)
  1866. for da in m:
  1867. curs.execute("select ip from topic where title = ? and sub = ? and id = ?", [name, sub, da])
  1868. row = curs.fetchall()
  1869. if(row):
  1870. if(not re.search('(\.|:)', row[0][0])):
  1871. curs.execute('insert into alarm (name, data, date) values (?, ?, ?)', [row[0][0], ip + '님이 <a href="/topic/' + url_pas(name) + '/sub/' + url_pas(sub) + '#' + str(num) + '">토론</a>에서 언급 했습니다.', today])
  1872. data = re.sub("(?P<in>#(?:[0-9]+))", '[[\g<in>]]', data)
  1873. data = savemark(data)
  1874. curs.execute("insert into topic (id, title, sub, data, date, ip, block, top) values (?, ?, ?, ?, ?, ?, '', '')", [str(num), name, sub, data, today, ip])
  1875. conn.commit()
  1876. return(redirect('/topic/' + url_pas(name) + '/sub/' + url_pas(sub)))
  1877. else:
  1878. style = ''
  1879. div = ''
  1880. curs.execute("select title from stop where title = ? and sub = ? and close = 'O'", [name, sub])
  1881. close = curs.fetchall()
  1882. curs.execute("select title from stop where title = ? and sub = ? and close = ''", [name, sub])
  1883. stop = curs.fetchall()
  1884. if(admin == 1):
  1885. if(close):
  1886. div += '<a href="/topic/' + url_pas(name) + '/sub/' + url_pas(sub) + '/tool/close">(토론 열기)</a> '
  1887. else:
  1888. div += '<a href="/topic/' + url_pas(name) + '/sub/' + url_pas(sub) + '/tool/close">(토론 닫기)</a> '
  1889. if(stop):
  1890. div += '<a href="/topic/' + url_pas(name) + '/sub/' + url_pas(sub) + '/tool/stop">(토론 재개)</a> '
  1891. else:
  1892. div += '<a href="/topic/' + url_pas(name) + '/sub/' + url_pas(sub) + '/tool/stop">(토론 정지)</a> '
  1893. curs.execute("select title from agreedis where title = ? and sub = ?", [name, sub])
  1894. agree = curs.fetchall()
  1895. if(agree):
  1896. div += '<a href="/topic/' + url_pas(name) + '/sub/' + url_pas(sub) + '/tool/agree">(합의 취소)</a>'
  1897. else:
  1898. div += '<a href="/topic/' + url_pas(name) + '/sub/' + url_pas(sub) + '/tool/agree">(합의 완료)</a>'
  1899. div += '<br><br>'
  1900. if((stop or close) and admin != 1):
  1901. style = 'display:none;'
  1902. curs.execute("select data, id, date, ip, block, top from topic where title = ? and sub = ? order by id + 0 asc", [name, sub])
  1903. toda = curs.fetchall()
  1904. curs.execute("select data, id, date, ip from topic where title = ? and sub = ? and top = 'O' order by id + 0 asc", [name, sub])
  1905. top = curs.fetchall()
  1906. for dain in top:
  1907. top_data = namumark('', dain[0], 0, 0, 0)
  1908. ip = ip_pas(dain[3], 1)
  1909. chad = ''
  1910. curs.execute("select who from re_admin where what = ? order by time desc limit 1", ['notice (' + name + ' - ' + sub + '#' + dain[1] + ')'])
  1911. no_da = curs.fetchall()
  1912. if(no_da):
  1913. chad += ' @' + no_da[0][0]
  1914. div += '<table id="toron"> \
  1915. <tbody> \
  1916. <tr> \
  1917. <td id="toron_color_red"> \
  1918. <a href="#' + dain[1] + '">#' + dain[1] + '</a> ' + ip + chad + ' <span style="float:right;">' + dain[2] + '</span> \
  1919. </td> \
  1920. </tr> \
  1921. <tr> \
  1922. <td>' + top_data + '</td> \
  1923. </tr> \
  1924. </tbody> \
  1925. </table> \
  1926. <br>'
  1927. i = 0
  1928. for dain in toda:
  1929. if(i == 0):
  1930. start = dain[3]
  1931. indata = dain[0]
  1932. if(dain[4] == 'O'):
  1933. block = 'style="background: gainsboro;"'
  1934. if(admin != 1):
  1935. curs.execute("select who from re_admin where what = ? order by time desc limit 1", ['blind (' + name + ' - ' + sub + '#' + str(i + 1) + ')'])
  1936. bl_da = curs.fetchall()
  1937. if(bl_da):
  1938. indata = '[[사용자:' + bl_da[0][0] + ']]님이 가림'
  1939. else:
  1940. indata = '관리자가 가림'
  1941. else:
  1942. block = ''
  1943. indata = namumark('', indata, 0, 0, 0)
  1944. if(admin == 1):
  1945. if(dain[4] == 'O'):
  1946. is_ban = ' <a href="/topic/' + url_pas(name) + '/sub/' + url_pas(sub) + '/b/' + str(i + 1) + '">(해제)</a>'
  1947. else:
  1948. is_ban = ' <a href="/topic/' + url_pas(name) + '/sub/' + url_pas(sub) + '/b/' + str(i + 1) + '">(가림)</a>'
  1949. curs.execute("select id from topic where title = ? and sub = ? and id = ? and top = 'O'", [name, sub, str(i + 1)])
  1950. row = curs.fetchall()
  1951. if(row):
  1952. is_ban = is_ban + ' <a href="/topic/' + url_pas(name) + '/sub/' + url_pas(sub) + '/notice/' + str(i + 1) + '">(해제)</a>'
  1953. else:
  1954. is_ban = is_ban + ' <a href="/topic/' + url_pas(name) + '/sub/' + url_pas(sub) + '/notice/' + str(i + 1) + '">(공지)</a>'
  1955. curs.execute("select end from ban where block = ?", [dain[3]])
  1956. ban_it = curs.fetchall()
  1957. if(ban_it):
  1958. ban = ' <a href="/ban/' + url_pas(dain[3]) + '">(해제)</a>' + is_ban
  1959. else:
  1960. ban = ' <a href="/ban/' + url_pas(dain[3]) + '">(차단)</a>' + is_ban
  1961. else:
  1962. curs.execute("select end from ban where block = ?", [dain[3]])
  1963. ban_it = curs.fetchall()
  1964. if(ban_it):
  1965. ban = ' <a href="javascript:void(0);" title="차단자">†</a>'
  1966. else:
  1967. ban = ''
  1968. ip = ip_pas(dain[3], 1)
  1969. curs.execute('select acl from user where id = ?', [dain[3]])
  1970. user_acl = curs.fetchall()
  1971. if(user_acl and user_acl[0][0] != 'user'):
  1972. ip += ' <a href="javascript:void(0);" title="관리자">★</a>'
  1973. if(admin == 1 or block == ''):
  1974. ip += ' <a href="/topic/' + url_pas(name) + '/sub/' + url_pas(sub) + '/raw/' + str(i + 1) + '">(원본)</a>'
  1975. if(dain[5] == '1'):
  1976. color = '_blue'
  1977. elif(dain[3] == start):
  1978. color = '_green'
  1979. else:
  1980. color = ''
  1981. if(indata == ''):
  1982. indata = '<br>'
  1983. div += '<table id="toron"> \
  1984. <tbody> \
  1985. <tr> \
  1986. <td id="toron_color' + color + '"> \
  1987. <a href="javascript:void(0);" id="' + str(i + 1) + '">#' + str(i + 1) + '</a> ' + ip + ban + ' <span style="float:right;">' + dain[2] + '</span> \
  1988. </td> \
  1989. </tr> \
  1990. <tr ' + block + '> \
  1991. <td>' + indata + '</td> \
  1992. </tr> \
  1993. </tbody> \
  1994. </table> \
  1995. <br>'
  1996. i += 1
  1997. l_c = login_check()
  1998. if(ban != 1):
  1999. data = '<a id="reload" href="javascript:void(0);" onclick="location.href.endsWith(\'#reload\') ? location.reload(true) : location.href = \'#reload\'"> \
  2000. <i aria-hidden="true" class="fa fa-refresh"></i> \
  2001. </a> \
  2002. <form style="' + style + '" method="post"> \
  2003. <br> \
  2004. <textarea style="width: 100%; height: 100px;" name="content"></textarea> \
  2005. <br> \
  2006. <br> \
  2007. <button class="btn btn-primary" type="submit">전송</button> \
  2008. </form>'
  2009. if(l_c == 0 and style == ''):
  2010. data += '<span>비 로그인 상태입니다. 비 로그인으로 작업 시 아이피가 토론에 기록됩니다.</span>'
  2011. else:
  2012. data = ''
  2013. return(
  2014. html_minify(
  2015. template('index',
  2016. imp = [name, wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), ' (토론)', 0],
  2017. data = '<h2 style="margin-top: 0px;">' + sub + '</h2> \
  2018. <br> \
  2019. ' + div + ' \
  2020. ' + data,
  2021. menu = [['topic/' + url_pas(name), '목록']]
  2022. )
  2023. )
  2024. )
  2025. @route('/topic/<name:path>', method=['POST', 'GET'])
  2026. @route('/topic/<name:path>/<tool:path>', method=['GET'])
  2027. def close_topic_list(name = None, tool = None):
  2028. div = ''
  2029. i = 0
  2030. list_d = 0
  2031. if(request.method == 'POST'):
  2032. t_num = ''
  2033. while(1):
  2034. curs.execute("select title from topic where title = ? and sub = ? limit 1", [name, request.forms.topic + t_num])
  2035. t_data = curs.fetchall()
  2036. if(t_data):
  2037. if(t_num == ''):
  2038. t_num = ' 2'
  2039. else:
  2040. t_num = ' ' + str(int(t_num.replace(' ', '')) + 1)
  2041. else:
  2042. break
  2043. return(redirect('/topic/' + url_pas(name) + '/sub/' + url_pas(request.forms.topic + t_num)))
  2044. else:
  2045. plus = ''
  2046. menu = [['topic/' + url_pas(name), '목록']]
  2047. if(tool == 'close'):
  2048. curs.execute("select sub from stop where title = ? and close = 'O' order by sub asc", [name])
  2049. sub = '닫힘'
  2050. elif(tool == 'agree'):
  2051. curs.execute("select sub from agreedis where title = ? order by sub asc", [name])
  2052. sub = '합의'
  2053. else:
  2054. curs.execute("select sub from rd where title = ? order by date desc", [name])
  2055. sub = '토론 목록'
  2056. menu = [['w/' + url_pas(name), '문서']]
  2057. plus = '<br> \
  2058. <a href="/topic/' + url_pas(name) + '/close">(닫힘)</a> <a href="/topic/' + url_pas(name) + '/agree">(합의)</a> \
  2059. <br> \
  2060. <br> \
  2061. <input placeholder="토론명" class="form-control" name="topic" style="width: 100%;"> \
  2062. <br> \
  2063. <br> \
  2064. <button class="btn btn-primary" type="submit">만들기</button>'
  2065. rows = curs.fetchall()
  2066. for data in rows:
  2067. curs.execute("select data, date, ip, block from topic where title = ? and sub = ? and id = '1'", [name, data[0]])
  2068. row = curs.fetchall()
  2069. if(row):
  2070. it_p = 0
  2071. if(sub == '토론 목록'):
  2072. curs.execute("select title from stop where title = ? and sub = ? and close = 'O' order by sub asc", [name, data[0]])
  2073. close = curs.fetchall()
  2074. if(close):
  2075. it_p = 1
  2076. if(it_p != 1):
  2077. div += '<h2> \
  2078. <a href="/topic/' + url_pas(name) + '/sub/' + url_pas(data[0]) + '">' + str((i + 1)) + '. ' + data[0] + '</a> \
  2079. </h2>'
  2080. i += 1
  2081. return(
  2082. html_minify(
  2083. template('index',
  2084. imp = [name, wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), ' (' + sub + ')', 0],
  2085. data = '<form style="margin-top: 0px;" method="post"> \
  2086. ' + div + plus + ' \
  2087. </form>',
  2088. menu = menu
  2089. )
  2090. )
  2091. )
  2092. @route('/login', method=['POST', 'GET'])
  2093. def login():
  2094. session = request.environ.get('beaker.session')
  2095. agent = request.environ.get('HTTP_USER_AGENT')
  2096. ip = ip_check()
  2097. ban = ban_check()
  2098. if(request.method == 'POST'):
  2099. if(ban == 1):
  2100. return(redirect('/ban'))
  2101. curs.execute("select pw from user where id = ?", [request.forms.id])
  2102. user = curs.fetchall()
  2103. if(user):
  2104. if(session.get('Now') == 1):
  2105. return(redirect('/error/11'))
  2106. if(bcrypt.checkpw(bytes(request.forms.pw, 'utf-8'), bytes(user[0][0], 'utf-8'))):
  2107. session['Now'] = 1
  2108. session['DREAMER'] = request.forms.id
  2109. curs.execute("select css from custom where user = ?", [request.forms.id])
  2110. css_data = curs.fetchall()
  2111. if(css_data):
  2112. session['Daydream'] = css_data[0][0]
  2113. else:
  2114. session['Daydream'] = ''
  2115. curs.execute("insert into ua_d (name, ip, ua, today, sub) values (?, ?, ?, ?, '')", [request.forms.id, ip, agent, get_time()])
  2116. conn.commit()
  2117. return(redirect('/user'))
  2118. else:
  2119. return(redirect('/error/10'))
  2120. else:
  2121. return(redirect('/error/5'))
  2122. else:
  2123. if(ban == 1):
  2124. return(redirect('/ban'))
  2125. if(session.get('Now') == 1):
  2126. return(redirect('/error/11'))
  2127. return(
  2128. html_minify(
  2129. template('index',
  2130. imp = ['로그인', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  2131. data = '<form method="post"> \
  2132. <input placeholder="아이디" name="id" type="text"> \
  2133. <br> \
  2134. <br> \
  2135. <input placeholder="비밀번호" name="pw" type="password"> \
  2136. <br> \
  2137. <br> \
  2138. <button class="btn btn-primary" type="submit">로그인</button> \
  2139. <br> \
  2140. <br> \
  2141. <span>주의 : 만약 HTTPS 연결이 아닌 경우 데이터가 유출될 가능성이 있습니다. 이에 대해 책임지지 않습니다.</span> \
  2142. </form>',
  2143. menu = [['user', '사용자']]
  2144. )
  2145. )
  2146. )
  2147. @route('/change', method=['POST', 'GET'])
  2148. def change_password():
  2149. ip = ip_check()
  2150. ban = ban_check()
  2151. if(request.method == 'POST'):
  2152. if(request.forms.pw2 == request.forms.pw3):
  2153. if(ban == 1):
  2154. return(redirect('/ban'))
  2155. curs.execute("select pw from user where id = ?", [request.forms.id])
  2156. user = curs.fetchall()
  2157. if(user):
  2158. if(re.search('(\.|:)', ip)):
  2159. return(redirect('/login'))
  2160. if(bcrypt.checkpw(bytes(request.forms.pw, 'utf-8'), bytes(user[0][0], 'utf-8'))):
  2161. hashed = bcrypt.hashpw(bytes(request.forms.pw2, 'utf-8'), bcrypt.gensalt())
  2162. curs.execute("update user set pw = ? where id = ?", [hashed.decode(), request.forms.id])
  2163. conn.commit()
  2164. return(redirect('/user'))
  2165. else:
  2166. return(redirect('/error/10'))
  2167. else:
  2168. return(redirect('/error/5'))
  2169. else:
  2170. return(redirect('/error/20'))
  2171. else:
  2172. if(ban == 1):
  2173. return(redirect('/ban'))
  2174. if(re.search('(\.|:)', ip)):
  2175. return(redirect('/login'))
  2176. return(
  2177. html_minify(
  2178. template('index',
  2179. imp = ['비밀번호 변경', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  2180. data = '<form method="post"> \
  2181. <input placeholder="아이디" name="id" type="text"> \
  2182. <br> \
  2183. <br> \
  2184. <input placeholder="현재 비밀번호" name="pw" type="password"> \
  2185. <br> \
  2186. <br> \
  2187. <input placeholder="변경할 비밀번호" name="pw2" type="password"> \
  2188. <br> \
  2189. <br> \
  2190. <input placeholder="재 확인" name="pw3" type="password"> \
  2191. <br> \
  2192. <br> \
  2193. <button class="btn btn-primary" type="submit">변경</button> \
  2194. <br> \
  2195. <br> \
  2196. <span>주의 : 만약 HTTPS 연결이 아닌 경우 데이터가 유출될 가능성이 있습니다. 이에 대해 책임지지 않습니다.</span> \
  2197. </form>',
  2198. menu = [['user', '사용자']]
  2199. )
  2200. )
  2201. )
  2202. @route('/check/<name:path>')
  2203. @route('/check/<name:path>/<name2:path>')
  2204. def user_check(name = None, name2 = None):
  2205. curs.execute("select acl from user where id = ? or id = ?", [name, name2])
  2206. user = curs.fetchall()
  2207. if(user and user[0][0] != 'user'):
  2208. if(admin_check(None, None) != 1):
  2209. return(redirect('/error/4'))
  2210. if(admin_check(4, 'check (' + name + ')') == 1):
  2211. if(name2):
  2212. if(re.search('(?:\.|:)', name)):
  2213. if(re.search('(?:\.|:)', name2)):
  2214. curs.execute("select name, ip, ua, today from ua_d where ip = ? or ip = ? order by today desc", [name, name2])
  2215. else:
  2216. curs.execute("select name, ip, ua, today from ua_d where ip = ? or name = ? order by today desc", [name, name2])
  2217. else:
  2218. if(re.search('(?:\.|:)', name2)):
  2219. curs.execute("select name, ip, ua, today from ua_d where name = ? or ip = ? order by today desc", [name, name2])
  2220. else:
  2221. curs.execute("select name, ip, ua, today from ua_d where name = ? or name = ? order by today desc", [name, name2])
  2222. elif(re.search('(?:\.|:)', name)):
  2223. curs.execute("select name, ip, ua, today from ua_d where ip = ? order by today desc", [name])
  2224. else:
  2225. curs.execute("select name, ip, ua, today from ua_d where name = ? order by today desc", [name])
  2226. row = curs.fetchall()
  2227. if(row):
  2228. c = '<table style="width: 100%; text-align: center;"> \
  2229. <tbody> \
  2230. <tr> \
  2231. <td style="width: 33.3%;">이름</td> \
  2232. <td style="width: 33.3%;">아이피</td> \
  2233. <td style="width: 33.3%;">언제</td> \
  2234. </tr>'
  2235. for data in row:
  2236. if(data[2]):
  2237. ua = data[2]
  2238. else:
  2239. ua = '<br>'
  2240. c += '<tr> \
  2241. <td>' + ip_pas(data[0], 2) + '</td> \
  2242. <td>' + ip_pas(data[1], 2) + '</td> \
  2243. <td>' + data[3] + '</td> \
  2244. </tr> \
  2245. <tr><td colspan="3">' + ua + '</td></tr>'
  2246. else:
  2247. c += '</tbody> \
  2248. </table>'
  2249. else:
  2250. c = ''
  2251. return(
  2252. html_minify(
  2253. template('index',
  2254. imp = ['다중 검사', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  2255. data = c,
  2256. menu = [['manager', '관리자']]
  2257. )
  2258. )
  2259. )
  2260. else:
  2261. return(redirect('/error/3'))
  2262. @route('/register', method=['POST', 'GET'])
  2263. def register():
  2264. ip = ip_check()
  2265. ban = ban_check()
  2266. if(ban == 1):
  2267. return(redirect('/ban'))
  2268. if(request.method == 'POST'):
  2269. if(request.forms.pw == request.forms.pw2):
  2270. m = re.search('(?:[^A-Za-zㄱ-힣0-9 ])', request.forms.id)
  2271. if(m):
  2272. return(redirect('/error/8'))
  2273. if(len(request.forms.id) > 32):
  2274. return(redirect('/error/7'))
  2275. curs.execute("select id from user where id = ?", [request.forms.id])
  2276. rows = curs.fetchall()
  2277. if(rows):
  2278. return(redirect('/error/6'))
  2279. hashed = bcrypt.hashpw(bytes(request.forms.pw, 'utf-8'), bcrypt.gensalt())
  2280. curs.execute("select id from user limit 1")
  2281. user_ex = curs.fetchall()
  2282. if(not user_ex):
  2283. curs.execute("insert into user (id, pw, acl) values (?, ?, '소유자')", [request.forms.id, hashed.decode()])
  2284. else:
  2285. curs.execute("insert into user (id, pw, acl) values (?, ?, 'user')", [request.forms.id, hashed.decode()])
  2286. conn.commit()
  2287. return(redirect('/login'))
  2288. else:
  2289. return(redirect('/error/20'))
  2290. else:
  2291. p = ''
  2292. curs.execute('select data from other where name = "contract"')
  2293. d = curs.fetchall()
  2294. if(d):
  2295. if(d[0][0] != ''):
  2296. p = d[0][0] + '<br><br>'
  2297. return(
  2298. html_minify(
  2299. template('index',
  2300. imp = ['회원가입', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  2301. data = '<form method="post"> \
  2302. ' + p + ' \
  2303. <input placeholder="아이디" name="id" type="text"> \
  2304. <br> \
  2305. <br> \
  2306. <input placeholder="비밀번호" name="pw" type="password"> \
  2307. <br> \
  2308. <br> \
  2309. <input placeholder="재 확인" name="pw2" type="password"> \
  2310. <br> \
  2311. <br> \
  2312. <button class="btn btn-primary" type="submit">가입</button> \
  2313. <br> \
  2314. <br> \
  2315. <span>주의 : 만약 HTTPS 연결이 아닌 경우 데이터가 유출될 가능성이 있습니다. 이에 대해 책임지지 않습니다.</span> \
  2316. </form>',
  2317. menu = [['user', '사용자']]
  2318. )
  2319. )
  2320. )
  2321. @route('/logout')
  2322. def logout():
  2323. session = request.environ.get('beaker.session')
  2324. session['Now'] = 0
  2325. session.pop('DREAMER', None)
  2326. return(redirect('/user'))
  2327. @route('/ban/<name:path>', method=['POST', 'GET'])
  2328. def user_ban(name = None):
  2329. curs.execute("select acl from user where id = ?", [name])
  2330. user = curs.fetchall()
  2331. if(user and user[0][0] != 'user'):
  2332. if(admin_check(None, None) != 1):
  2333. return(redirect('/error/4'))
  2334. if(request.method == 'POST'):
  2335. if(admin_check(1, 'ban (' + name + ')') == 1):
  2336. ip = ip_check()
  2337. if(request.forms.year == '09'):
  2338. end = ''
  2339. else:
  2340. end = request.forms.year + '-' + request.forms.month + '-' + request.forms.day
  2341. curs.execute("select block from ban where block = ?", [name])
  2342. row = curs.fetchall()
  2343. if(row):
  2344. rb_plus(name, '해제', get_time(), ip, '')
  2345. curs.execute("delete from ban where block = ?", [name])
  2346. else:
  2347. b = re.search("^([0-9]{1,3}\.[0-9]{1,3})$", name)
  2348. if(b):
  2349. band_d = 'O'
  2350. else:
  2351. band_d = ''
  2352. rb_plus(name, end, get_time(), ip, request.forms.why)
  2353. curs.execute("insert into ban (block, end, why, band) values (?, ?, ?, ?)", [name, end, request.forms.why, band_d])
  2354. conn.commit()
  2355. return(redirect('/ban/' + url_pas(name)))
  2356. else:
  2357. return(redirect('/error/3'))
  2358. else:
  2359. if(admin_check(1, None) == 1):
  2360. curs.execute("select * from ban where block = ?", [name])
  2361. row = curs.fetchall()
  2362. if(row):
  2363. now = '차단 해제'
  2364. data = ''
  2365. else:
  2366. b = re.search("^([0-9]{1,3}\.[0-9]{1,3})$", name)
  2367. if(b):
  2368. now = '대역 차단'
  2369. else:
  2370. now = '차단'
  2371. year_n = int("%04d" % (time.localtime().tm_year))
  2372. year = '<option value="09">영구</option>'
  2373. for i in range(year_n, year_n + 51):
  2374. if(i == year_n):
  2375. year += '<option value="' + str(i) + '" selected>' + str(i) + '</option>'
  2376. else:
  2377. year += '<option value="' + str(i) + '">' + str(i) + '</option>'
  2378. month = '<option value="1" selected>1</option>'
  2379. for i in range(2, 13):
  2380. month += '<option value="' + str(i) + '">' + str(i) + '</option>'
  2381. day = '<option value="1" selected>1</option>'
  2382. for i in range(2, 32):
  2383. day += '<option value="' + str(i) + '">' + str(i) + '</option>'
  2384. data = '<select name="year"> \
  2385. ' + year + ' \
  2386. </select> \
  2387. <select name="month"> \
  2388. ' + month + ' \
  2389. </select> \
  2390. <select name="day"> \
  2391. ' + day + ' \
  2392. </select> \
  2393. <br> \
  2394. <br> \
  2395. <input placeholder="사유" class="form-control" name="why" style="width: 100%;"> \
  2396. <br> \
  2397. <br>'
  2398. return(
  2399. html_minify(
  2400. template('index',
  2401. imp = [name, wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), ' (' + now + ')', 0],
  2402. data = '<form method="post"> \
  2403. ' + data + ' \
  2404. <button class="btn btn-primary" type="submit">' + now + '</button> \
  2405. </form>',
  2406. menu = [['manager', '관리자']]
  2407. )
  2408. )
  2409. )
  2410. else:
  2411. return(redirect('/error/3'))
  2412. @route('/user_acl/<name:path>', method=['POST', 'GET'])
  2413. def acl(name = None):
  2414. ip = ip_check()
  2415. if(ip != name or re.search("(\.|:)", name)):
  2416. return(redirect('/error/3'))
  2417. if(request.method == 'POST'):
  2418. curs.execute("select acl from data where title = ?", ['사용자:' + name])
  2419. acl_d = curs.fetchall()
  2420. if(acl_d):
  2421. if(request.forms.select == 'all'):
  2422. curs.execute("update data set acl = 'all' where title = ?", ['사용자:' + name])
  2423. elif(request.forms.select == 'user'):
  2424. curs.execute("update data set acl = 'user' where title = ?", ['사용자:' + name])
  2425. else:
  2426. curs.execute("update data set acl = '' where title = ?", ['사용자:' + name])
  2427. conn.commit()
  2428. return(redirect('/w/' + url_pas('사용자:' + name)))
  2429. curs.execute("select acl from data where title = ?", ['사용자:' + name])
  2430. acl_d = curs.fetchall()
  2431. if(acl_d):
  2432. if(acl_d[0][0] == 'all'):
  2433. now = '모두'
  2434. elif(acl_d[0][0] == 'user'):
  2435. now = '로그인'
  2436. else:
  2437. now = '일반'
  2438. return(
  2439. html_minify(
  2440. template('index',
  2441. imp = [name, wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), ' (SET)', 0],
  2442. data = '<span>현재 ACL : ' + now + '</span> \
  2443. <br> \
  2444. <br> \
  2445. <form method="post"> \
  2446. <select name="select"> \
  2447. <option value="all">모두</option> \
  2448. <option value="user">로그인</option> \
  2449. <option value="normal" selected="selected">일반</option> \
  2450. </select> \
  2451. <br> \
  2452. <br> \
  2453. <button class="btn btn-primary" type="submit">ACL 변경</button> \
  2454. </form>',
  2455. menu = [['user', '사용자']]
  2456. )
  2457. )
  2458. )
  2459. else:
  2460. return(redirect('/w/' + url_pas(name)))
  2461. @route('/acl/<name:path>', method=['POST', 'GET'])
  2462. def acl(name = None):
  2463. if(request.method == 'POST'):
  2464. if(admin_check(5, 'acl (' + name + ')') == 1):
  2465. curs.execute("select acl from data where title = ?", [name])
  2466. row = curs.fetchall()
  2467. if(row):
  2468. if(request.forms.select == 'admin'):
  2469. curs.execute("update data set acl = 'admin' where title = ?", [name])
  2470. elif(request.forms.select == 'user'):
  2471. curs.execute("update data set acl = 'user' where title = ?", [name])
  2472. else:
  2473. curs.execute("update data set acl = '' where title = ?", [name])
  2474. conn.commit()
  2475. return(redirect('/w/' + url_pas(name)))
  2476. else:
  2477. return(redirect('/error/3'))
  2478. else:
  2479. if(admin_check(5, None) == 1):
  2480. curs.execute("select acl from data where title = ?", [name])
  2481. row = curs.fetchall()
  2482. if(row):
  2483. if(row[0][0] == 'admin'):
  2484. now = '관리자'
  2485. elif(row[0][0] == 'user'):
  2486. now = '로그인'
  2487. else:
  2488. now = '일반'
  2489. return(
  2490. html_minify(
  2491. template('index',
  2492. imp = [name, wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), ' (ACL)', 0],
  2493. data = '<span>현재 ACL : ' + now + '</span> \
  2494. <br> \
  2495. <br> \
  2496. <form method="post"> \
  2497. <select name="select"> \
  2498. <option value="admin" selected="selected">관리자</option> \
  2499. <option value="user">로그인</option> \
  2500. <option value="normal">일반</option> \
  2501. </select> \
  2502. <br> \
  2503. <br> \
  2504. <button class="btn btn-primary" type="submit">ACL 변경</button> \
  2505. </form>',
  2506. menu = [['w/' + url_pas(name), '문서'], ['manager', '관리자']]
  2507. )
  2508. )
  2509. )
  2510. else:
  2511. return(redirect('/w/' + url_pas(name)) )
  2512. else:
  2513. return(redirect('/error/3'))
  2514. @route('/admin/<name:path>', method=['POST', 'GET'])
  2515. def user_admin(name = None):
  2516. if(request.method == 'POST'):
  2517. if(admin_check(None, 'admin (' + name + ')') == 1):
  2518. if(request.forms.select == 'X'):
  2519. curs.execute("update user set acl = 'user' where id = ?", [name])
  2520. else:
  2521. curs.execute("update user set acl = ? where id = ?", [request.forms.select, name])
  2522. conn.commit()
  2523. return(redirect('/admin/' + url_pas(name)))
  2524. else:
  2525. return(redirect('/error/3'))
  2526. else:
  2527. if(admin_check(None, None) == 1):
  2528. curs.execute("select acl from user where id = ?", [name])
  2529. user = curs.fetchall()
  2530. if(user):
  2531. div = '<option value="X">X</option>'
  2532. curs.execute('select name from alist order by name asc')
  2533. get_alist = curs.fetchall()
  2534. if(get_alist):
  2535. i = 0
  2536. name_rem = ''
  2537. for data in get_alist:
  2538. if(name_rem != data[0]):
  2539. name_rem = data[0]
  2540. if(user[0][0] == data[0]):
  2541. div += '<option value="' + data[0] + '" selected="selected">' + data[0] + '</option>'
  2542. else:
  2543. div += '<option value="' + data[0] + '">' + data[0] + '</option>'
  2544. return(
  2545. html_minify(
  2546. template('index',
  2547. imp = [name, wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), ' (권한 부여)', 0],
  2548. data = '<form method="post"> \
  2549. <select name="select"> \
  2550. ' + div + ' \
  2551. </select> \
  2552. <br> \
  2553. <br> \
  2554. <button class="btn btn-primary" type="submit">변경</button> \
  2555. </form>',
  2556. menu = [['manager', '관리자']]
  2557. )
  2558. )
  2559. )
  2560. else:
  2561. return(redirect('/error/5'))
  2562. else:
  2563. return(redirect('/error/3'))
  2564. @route('/ban')
  2565. def are_you_ban():
  2566. ip = ip_check()
  2567. if(ban_check() == 1):
  2568. curs.execute("select end, why from ban where block = ?", [ip])
  2569. rows = curs.fetchall()
  2570. if(not rows):
  2571. data = re.search("^([0-9](?:[0-9]?[0-9]?)\.[0-9](?:[0-9]?[0-9]?))", ip)
  2572. if(data):
  2573. results = data.groups()
  2574. curs.execute("select end, why from ban where block = ? and band = 'O'", [results[0]])
  2575. rows = curs.fetchall()
  2576. if(rows):
  2577. if(rows[0][0]):
  2578. end = rows[0][0] + ' 까지 차단 상태 입니다. / 사유 : ' + rows[0][1]
  2579. now = re.sub(':', '', get_time())
  2580. now = re.sub('\-', '', now)
  2581. now = int(re.sub(' ', '', now))
  2582. day = re.sub('\-', '', rows[0][0])
  2583. if(now >= int(day + '000000')):
  2584. curs.execute("delete from ban where block = ?", [ip])
  2585. conn.commit()
  2586. end = '차단이 풀렸습니다. 다시 시도 해 보세요.'
  2587. else:
  2588. end = '영구 차단 상태 입니다. / 사유 : ' + rows[0][1]
  2589. else:
  2590. end = '권한이 맞지 않는 상태 입니다.'
  2591. else:
  2592. end = '권한이 맞지 않는 상태 입니다.'
  2593. return(
  2594. html_minify(
  2595. template('index',
  2596. imp = ['권한 오류', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  2597. data = end,
  2598. menu = 0
  2599. )
  2600. )
  2601. )
  2602. @route('/w/<name:path>/r/<a:int>/diff/<b:int>')
  2603. def diff_data(name = None, a = None, b = None):
  2604. curs.execute("select data from history where id = ? and title = ?", [str(a), name])
  2605. a_raw_data = curs.fetchall()
  2606. if(a_raw_data):
  2607. curs.execute("select data from history where id = ? and title = ?", [str(b), name])
  2608. b_raw_data = curs.fetchall()
  2609. if(b_raw_data):
  2610. a_data = html.escape(a_raw_data[0][0])
  2611. b_data = html.escape(b_raw_data[0][0])
  2612. if(a_data == b_data):
  2613. result = '내용이 같습니다.'
  2614. else:
  2615. diff_data = difflib.SequenceMatcher(None, a_data, b_data)
  2616. result_1 = diff(diff_data, 1)
  2617. result_2 = diff(diff_data, 0)
  2618. if(a_data == result_1):
  2619. result = '<pre>' + result_2 + '</pre>'
  2620. elif(b_data == result_2):
  2621. result = '<pre>' + result_1 + '</pre>'
  2622. else:
  2623. result = '<pre>' + result_1 + '<hr>' + result_2 + '</pre>'
  2624. return(
  2625. html_minify(
  2626. template('index',
  2627. imp = [name, wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), ' (비교)', 0],
  2628. data = result,
  2629. menu = [['history/' + url_pas(name), '역사']]
  2630. )
  2631. )
  2632. )
  2633. return(redirect('/history/' + url_pas(name)))
  2634. @route('/down/<name:path>')
  2635. def down(name = None):
  2636. curs.execute("select title from data where title like ?", ['%' + name + '/%'])
  2637. under = curs.fetchall()
  2638. div = '<ul>'
  2639. i = 0
  2640. for data in under:
  2641. div += '<li>' + str(i + 1) + '. <a href="/w/' + url_pas(data[0]) + '">' + data[0] + '</a></li>'
  2642. i += 1
  2643. div += '</ul>'
  2644. return(
  2645. html_minify(
  2646. template('index',
  2647. imp = [name, wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), ' (하위)', 0],
  2648. data = div,
  2649. menu = [['w/' + url_pas(name), '문서']]
  2650. )
  2651. )
  2652. )
  2653. @route('/w/<name:path>')
  2654. @route('/w/<name:path>/r/<num:int>')
  2655. @route('/w/<name:path>/from/<redirect:path>')
  2656. def read_view(name = None, num = None, redirect = None):
  2657. data_none = 0
  2658. sub = ''
  2659. acl = ''
  2660. div = ''
  2661. topic = 0
  2662. curs.execute("select sub from rd where title = ? order by date desc", [name])
  2663. rows = curs.fetchall()
  2664. for data in rows:
  2665. curs.execute("select title from stop where title = ? and sub = ? and close = 'O'", [name, data[0]])
  2666. row = curs.fetchall()
  2667. if(not row):
  2668. topic = 1
  2669. break
  2670. curs.execute("select title from data where title like ?", ['%' + name + '/%'])
  2671. under = curs.fetchall()
  2672. if(under):
  2673. down = 1
  2674. else:
  2675. down = 0
  2676. m = re.search("^(.*)\/(.*)$", name)
  2677. if(m):
  2678. uppage = m.groups()[0]
  2679. else:
  2680. uppage = 0
  2681. if(admin_check(5, None) == 1):
  2682. admin_memu = 1
  2683. else:
  2684. admin_memu = 0
  2685. if(re.search("^분류:", name)):
  2686. curs.execute("delete from cat where title = ? and cat = ''", [name])
  2687. conn.commit()
  2688. curs.execute("select cat from cat where title = ? order by cat asc", [name])
  2689. rows = curs.fetchall()
  2690. if(rows):
  2691. div = '[목차(없음)]\r\n== 분류 ==\r\n'
  2692. u_div = ''
  2693. i = 0
  2694. for data in rows:
  2695. if(re.search('^분류:', data[0])):
  2696. if(u_div == ''):
  2697. u_div = '=== 하위 분류 ===\r\n'
  2698. u_div += ' * [[:' + data[0] + ']]\r\n'
  2699. else:
  2700. div += ' * [[' + data[0] + ']]\r\n'
  2701. div += u_div
  2702. if(num):
  2703. curs.execute("select title from hidhi where title = ? and re = ?", [name, str(num)])
  2704. hid = curs.fetchall()
  2705. if(hid and admin_check(6, None) != 1):
  2706. return(redirect('/history/' + url_pas(name)))
  2707. curs.execute("select title, data from history where title = ? and id = ?", [name, str(num)])
  2708. else:
  2709. curs.execute("select acl, data from data where title = ?", [name])
  2710. rows = curs.fetchall()
  2711. if(rows):
  2712. if(not num):
  2713. if(rows[0][0] == 'admin'):
  2714. acl = ' (관리자)'
  2715. elif(rows[0][0] == 'user'):
  2716. acl = ' (로그인)'
  2717. elsedata = rows[0][1]
  2718. else:
  2719. data_none = 1
  2720. response.status = 404
  2721. elsedata = ''
  2722. m = re.search("^사용자:([^/]*)", name)
  2723. if(m):
  2724. g = m.groups()
  2725. curs.execute("select acl from user where id = ?", [g[0]])
  2726. test = curs.fetchall()
  2727. if(test and test[0][0] != 'user'):
  2728. acl = ' (관리자)'
  2729. else:
  2730. acl = ''
  2731. if(rows):
  2732. if(rows[0][0] == 'all'):
  2733. acl += ' (모두)'
  2734. elif(rows[0][0] == 'user'):
  2735. acl += ' (로그인)'
  2736. curs.execute("select block from ban where block = ?", [g[0]])
  2737. user = curs.fetchall()
  2738. if(user):
  2739. sub = ' (차단)'
  2740. if(redirect):
  2741. elsedata = re.sub("^#(?:redirect|넘겨주기) (?P<in>[^\n]*)", " * [[\g<in>]] 문서로 넘겨주기", elsedata)
  2742. enddata = namumark(name, elsedata, 0, 0, 1)
  2743. if(data_none == 1):
  2744. menu = [['edit/' + url_pas(name), '생성'], ['topic/' + url_pas(name), topic], ['history/' + url_pas(name), '역사'], ['move/' + url_pas(name), '이동'], ['xref/' + url_pas(name), '역링크']]
  2745. else:
  2746. menu = [['edit/' + url_pas(name), '수정'], ['topic/' + url_pas(name), topic], ['history/' + url_pas(name), '역사'], ['delete/' + url_pas(name), '삭제'], ['move/' + url_pas(name), '이동'], ['raw/' + url_pas(name), '원본'], ['xref/' + url_pas(name), '역링크']]
  2747. if(admin_memu == 1):
  2748. menu += [['acl/' + url_pas(name), 'ACL']]
  2749. if(redirect):
  2750. menu += [['w/' + url_pas(name), '넘기기']]
  2751. enddata = '<ul id="redirect"><li><a href="/w/' + url_pas(redirect) + '/from/' + url_pas(name) + '">' + redirect + '</a>에서 넘어 왔습니다.</li></ul><br>' + enddata
  2752. if(uppage != 0):
  2753. menu += [['w/' + url_pas(uppage), '상위']]
  2754. if(down):
  2755. menu += [['down/' + url_pas(name), '하위']]
  2756. if(num):
  2757. menu = [['history/' + url_pas(name), '역사']]
  2758. sub = ' (' + str(num) + '판)'
  2759. acl = ''
  2760. r_date = 0
  2761. else:
  2762. curs.execute("select date from history where title = ? order by date desc limit 1", [name])
  2763. date = curs.fetchall()
  2764. if(date):
  2765. r_date = date[0][0]
  2766. else:
  2767. r_date = 0
  2768. return(
  2769. html_minify(
  2770. template('index',
  2771. imp = [name, wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), sub + acl, r_date],
  2772. data = enddata + namumark(name, div, 0, 0, 0),
  2773. menu = menu
  2774. )
  2775. )
  2776. )
  2777. @route('/user/<name:path>/topic')
  2778. @route('/user/<name:path>/topic/<num:int>')
  2779. def user_topic_list(name = None, num = 1):
  2780. if(num * 50 <= 0):
  2781. v = 50
  2782. else:
  2783. v = num * 50
  2784. i = v - 50
  2785. ydmin = admin_check(1, None)
  2786. div = '<table style="width: 100%; text-align: center;"> \
  2787. <tbody> \
  2788. <tr> \
  2789. <td style="width: 33.3%;">토론명</td> \
  2790. <td style="width: 33.3%;">작성자</td> \
  2791. <td style="width: 33.3%;">시간</td> \
  2792. </tr>'
  2793. curs.execute("select title, id, sub, ip, date from topic where ip = ? order by date desc limit ?, ?", [name, str(i), str(v)])
  2794. rows = curs.fetchall()
  2795. if(rows):
  2796. for data in rows:
  2797. title = html.escape(data[0])
  2798. sub = html.escape(data[2])
  2799. if(ydmin == 1):
  2800. curs.execute("select * from ban where block = ?", [data[3]])
  2801. row = curs.fetchall()
  2802. if(row):
  2803. ban = ' <a href="/ban/' + url_pas(data[3]) + '">(해제)</a>'
  2804. else:
  2805. ban = ' <a href="/ban/' + url_pas(data[3]) + '">(차단)</a>'
  2806. else:
  2807. ban = ''
  2808. ip = ip_pas(data[3], 1)
  2809. div += '<tr> \
  2810. <td> \
  2811. <a href="/topic/' + url_pas(data[0]) + '/sub/' + url_pas(data[2]) + '#' + data[1] + '">' + title + '#' + data[1] + '</a> (' + sub + ') \
  2812. </td> \
  2813. <td>' + ip + ban + '</td> \
  2814. <td>' + data[4] + '</td> \
  2815. </tr>'
  2816. else:
  2817. div += '</tbody> \
  2818. </table>'
  2819. else:
  2820. div = ''
  2821. div += '<br><a href="/user/' + url_pas(name) + '/topic/' + str(num - 1) + '">(이전)</a> <a href="/user/' + url_pas(name) + '/topic/' + str(num + 1) + '">(이후)</a>'
  2822. curs.execute("select end, why from ban where block = ?", [name])
  2823. ban_it = curs.fetchall()
  2824. if(ban_it):
  2825. sub = ' (차단)'
  2826. else:
  2827. sub = 0
  2828. return(
  2829. html_minify(
  2830. template('index',
  2831. imp = ['토론 기록', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), sub, 0],
  2832. data = div,
  2833. menu = [['other', '기타'], ['user', '사용자']]
  2834. )
  2835. )
  2836. )
  2837. @route('/upload', method=['GET', 'POST'])
  2838. def upload():
  2839. if(ban_check() == 1):
  2840. return(redirect('/ban'))
  2841. if(request.method == 'POST'):
  2842. data = request.files.f_data
  2843. if(data):
  2844. if(int(wiki_set(4)) * 1024 * 1024 < request.content_length):
  2845. return redirect('/error/17')
  2846. value = os.path.splitext(data.filename)[1]
  2847. if(not value in ['.jpeg', '.jpg', '.gif', '.png', '.webp', '.JPEG', '.JPG', '.GIF', '.PNG', '.WEBP']):
  2848. return redirect('/error/14')
  2849. if(request.forms.get('f_name')):
  2850. name = request.forms.get('f_name') + value
  2851. else:
  2852. name = data.filename
  2853. piece = os.path.splitext(name)
  2854. e_data = sha224(piece[0]) + piece[1]
  2855. ip = ip_check()
  2856. if(request.forms.get('f_lice')):
  2857. lice = request.forms.get('f_lice')
  2858. else:
  2859. if(re.search('(?:\.|:)', ip)):
  2860. lice = ip + ' 올림'
  2861. else:
  2862. lice = '[[사용자:' + ip + ']] 올림'
  2863. if(os.path.exists(os.path.join('image', e_data))):
  2864. return(redirect('/error/16'))
  2865. data.save(os.path.join('image', e_data))
  2866. curs.execute("select title from data where title = ?", ['파일:' + name])
  2867. exist = curs.fetchall()
  2868. if(exist):
  2869. curs.execute("delete from data where title = ?", ['파일:' + name])
  2870. curs.execute("insert into data (title, data, acl) values (?, ?, 'admin')", ['파일:' + name, '[[파일:' + name + ']][br][br]{{{[[파일:' + name + ']]}}}[br][br]' + lice])
  2871. conn.commit()
  2872. history_plus(
  2873. '파일:' + name,
  2874. '[[파일:' + name + ']][br][br]{{{[[파일:' + name + ']]}}}[br][br]' + lice,
  2875. get_time(),
  2876. ip,
  2877. '(파일 올림)',
  2878. '0'
  2879. )
  2880. return(redirect('/w/파일:' + name))
  2881. else:
  2882. return(redirect('/error/9'))
  2883. else:
  2884. return(
  2885. html_minify(
  2886. template('index',
  2887. imp = ['파일 올리기', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  2888. data = '<form method="post" enctype="multipart/form-data" accept-charset="utf8"> \
  2889. <input type="file" name="f_data"> \
  2890. <br> \
  2891. <br> \
  2892. <input placeholder="파일 이름" name="f_name" type="text"> \
  2893. <br> \
  2894. <br> \
  2895. <input placeholder="라이선스" name="f_lice" type="text"> \
  2896. <br> \
  2897. <br> \
  2898. <span>원인 모를 버그로 한글이 되지 않습니다.</span> \
  2899. <br> \
  2900. <br> \
  2901. <button class="btn btn-primary" type="submit">저장</button> \
  2902. </form>',
  2903. menu = [['other', '기타']]
  2904. )
  2905. )
  2906. )
  2907. @route('/user')
  2908. def user_info():
  2909. ip = ip_check()
  2910. raw_ip = ip
  2911. curs.execute("select acl from user where id = ?", [ip])
  2912. rows = curs.fetchall()
  2913. if(ban_check() == 0):
  2914. if(rows):
  2915. if(rows[0][0] != 'user'):
  2916. acl = rows[0][0]
  2917. else:
  2918. acl = '로그인'
  2919. else:
  2920. acl = '일반'
  2921. else:
  2922. acl = '차단'
  2923. ip = ip_pas(ip, 2)
  2924. if(login_check() == 1):
  2925. plus = ' * [[wiki:logout|로그아웃]]'
  2926. else:
  2927. plus = ' * [[wiki:login|로그인]]'
  2928. return(
  2929. html_minify(
  2930. template('index',
  2931. imp = ['사용자 메뉴', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  2932. data = ip + '<br><br>' + namumark('', '권한 상태 : ' + acl + '\r\n' + \
  2933. '[목차(없음)]\r\n' + \
  2934. '== 로그인 ==\r\n' + \
  2935. plus + '\r\n' + \
  2936. ' * [[wiki:register|회원가입]]\r\n' + \
  2937. '== 사용자 ==\r\n' + \
  2938. ' * [[wiki:user_acl/' + url_pas(raw_ip) + '|사용자 문서 ACL]]\r\n' + \
  2939. ' * [[wiki:custom_css|사용자 CSS]]\r\n' + \
  2940. ' * [[wiki:custom_js|사용자 JS]]\r\n' + \
  2941. '== 기타 ==\r\n' + \
  2942. ' * [[wiki:alarm|알림]]\r\n' + \
  2943. ' * [[wiki:change|비밀번호 변경]]\r\n' + \
  2944. ' * [[wiki:count|기여 횟수]]\r\n', 0, 0, 0),
  2945. menu = 0
  2946. )
  2947. )
  2948. )
  2949. @route('/custom_css', method=['GET', 'POST'])
  2950. def custom_css_view():
  2951. session = request.environ.get('beaker.session')
  2952. ip = ip_check()
  2953. if(request.method == 'POST'):
  2954. if(not re.search('(\.|:)', ip)):
  2955. curs.execute("select * from custom where user = ?", [ip])
  2956. css_data = curs.fetchall()
  2957. if(css_data):
  2958. curs.execute("update custom set css = ? where user = ?", [request.forms.content, ip])
  2959. else:
  2960. curs.execute("insert into custom (user, css) values (?, ?)", [ip, request.forms.content])
  2961. conn.commit()
  2962. session['Daydream'] = request.forms.content
  2963. return(redirect('/user'))
  2964. else:
  2965. if(not re.search('(\.|:)', ip)):
  2966. start = ''
  2967. curs.execute("select css from custom where user = ?", [ip])
  2968. css_data = curs.fetchall()
  2969. if(css_data):
  2970. data = css_data[0][0]
  2971. else:
  2972. data = ''
  2973. else:
  2974. start = '<span>비 로그인의 경우에는 로그인하면 날아갑니다.</span><br><br>'
  2975. try:
  2976. data = session['Daydream']
  2977. except:
  2978. data = ''
  2979. return(
  2980. html_minify(
  2981. template('index',
  2982. imp = ['사용자 CSS', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  2983. data = start + ' \
  2984. <form method="post"> \
  2985. <textarea rows="30" cols="100" name="content">'\
  2986. + data + \
  2987. '</textarea> \
  2988. <br> \
  2989. <br> \
  2990. <div class="form-actions"> \
  2991. <button class="btn btn-primary" type="submit">저장</button> \
  2992. </div> \
  2993. </form>',
  2994. menu = [['user', '사용자']]
  2995. )
  2996. )
  2997. )
  2998. @route('/custom_js', method=['GET', 'POST'])
  2999. def custom_js_view():
  3000. session = request.environ.get('beaker.session')
  3001. ip = ip_check()
  3002. if(request.method == 'POST'):
  3003. if(not re.search('(\.|:)', ip)):
  3004. curs.execute("select * from custom where user = ?", [ip + ' (js)'])
  3005. js_data = curs.fetchall()
  3006. if(js_data):
  3007. curs.execute("update custom set css = ? where user = ?", [request.forms.content, ip + ' (js)'])
  3008. else:
  3009. curs.execute("insert into custom (user, css) values (?, ?)", [ip + ' (js)', request.forms.content])
  3010. conn.commit()
  3011. session['AQUARIUM'] = request.forms.content
  3012. return(redirect('/user'))
  3013. else:
  3014. if(not re.search('(\.|:)', ip)):
  3015. start = ''
  3016. curs.execute("select css from custom where user = ?", [ip + ' (js)'])
  3017. js_data = curs.fetchall()
  3018. if(js_data):
  3019. data = js_data[0][0]
  3020. else:
  3021. data = ''
  3022. else:
  3023. start = '<span>비 로그인의 경우에는 로그인하면 날아갑니다.</span><br><br>'
  3024. try:
  3025. data = session['AQUARIUM']
  3026. except:
  3027. data = ''
  3028. return(
  3029. html_minify(
  3030. template('index',
  3031. imp = ['사용자 JS', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  3032. data = start + ' \
  3033. <form method="post"> \
  3034. <textarea rows="30" cols="100" name="content">'\
  3035. + data + \
  3036. '</textarea> \
  3037. <br> \
  3038. <br> \
  3039. <div class="form-actions"> \
  3040. <button class="btn btn-primary" type="submit">저장</button> \
  3041. </div> \
  3042. </form>',
  3043. menu = [['user', '사용자']]
  3044. )
  3045. )
  3046. )
  3047. @route('/count')
  3048. @route('/count/<name:path>')
  3049. def count_edit(name = None):
  3050. if(name == None):
  3051. that = ip_check()
  3052. else:
  3053. that = name
  3054. curs.execute("select count(title) from history where ip = ?", [that])
  3055. count = curs.fetchall()
  3056. if(count):
  3057. data = count[0][0]
  3058. else:
  3059. data = 0
  3060. curs.execute("select count(title) from topic where ip = ?", [that])
  3061. count = curs.fetchall()
  3062. if(count):
  3063. t_data = count[0][0]
  3064. else:
  3065. t_data = 0
  3066. return(
  3067. html_minify(
  3068. template('index',
  3069. imp = ['기여 횟수', wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  3070. data = namumark("", "||<-2><:> " + that + " ||\r\n||<:> 기여 횟수 ||<:> " + str(data) + "||\r\n||<:> 토론 횟수 ||<:> " + str(t_data) + "||", 0, 0, 0),
  3071. menu = [['user', '사용자']]
  3072. )
  3073. )
  3074. )
  3075. @route('/random')
  3076. def random():
  3077. curs.execute("select title from data order by random() limit 1")
  3078. rows = curs.fetchall()
  3079. if(rows):
  3080. return(redirect('/w/' + url_pas(rows[0][0])))
  3081. else:
  3082. return(redirect('/'))
  3083. @route('/views/<name:path>')
  3084. def views(name = None):
  3085. if(re.search('\/', name)):
  3086. m = re.search('^(.*)\/(.*)$', name)
  3087. if(m):
  3088. n = m.groups()
  3089. plus = '/' + n[0]
  3090. rename = n[1]
  3091. else:
  3092. plus = ''
  3093. rename = name
  3094. else:
  3095. plus = ''
  3096. rename = name
  3097. return(
  3098. static_file(rename,
  3099. root = './views' + plus
  3100. )
  3101. )
  3102. @route('/error/<num:int>')
  3103. def error_test(num = None):
  3104. response.status = 404
  3105. if(num == 1):
  3106. title = '권한 오류'
  3107. data = '비 로그인 상태 입니다.'
  3108. elif(num == 2):
  3109. title = '권한 오류'
  3110. data = '이 계정이 없습니다.'
  3111. elif(num == 3):
  3112. title = '권한 오류'
  3113. data = '권한이 모자랍니다.'
  3114. elif(num == 4):
  3115. title = '권한 오류'
  3116. data = '관리자는 차단, 검사 할 수 없습니다.'
  3117. elif(num == 5):
  3118. title = '사용자 오류'
  3119. data = '그런 계정이 없습니다.'
  3120. elif(num == 6):
  3121. title = '가입 오류'
  3122. data = '동일한 아이디의 사용자가 있습니다.'
  3123. elif(num == 7):
  3124. title = '가입 오류'
  3125. data = '아이디는 20글자보다 짧아야 합니다.'
  3126. elif(num == 8):
  3127. title = '가입 오류'
  3128. data = '아이디에는 한글과 알파벳과 공백만 허용 됩니다.'
  3129. elif(num == 9):
  3130. title = '파일 올리기 오류'
  3131. data = '파일이 없습니다.'
  3132. elif(num == 10):
  3133. title = '변경 오류'
  3134. data = '비밀번호가 다릅니다.'
  3135. elif(num == 11):
  3136. title = '로그인 오류'
  3137. data = '이미 로그인 되어 있습니다.'
  3138. elif(num == 14):
  3139. title = '파일 올리기 오류'
  3140. data = 'jpg, gif, jpeg, png, webp만 가능 합니다.'
  3141. elif(num == 15):
  3142. title = '편집 오류'
  3143. data = '편집 기록은 500자를 넘을 수 없습니다.'
  3144. elif(num == 16):
  3145. title = '파일 올리기 오류'
  3146. data = '동일한 이름의 파일이 있습니다.'
  3147. elif(num == 17):
  3148. title = '파일 올리기 오류'
  3149. data = '파일 용량은 ' + wiki_set(4) + 'MB를 넘길 수 없습니다.'
  3150. elif(num == 18):
  3151. title = '편집 오류'
  3152. data = '내용이 원래 문서와 동일 합니다.'
  3153. elif(num == 19):
  3154. title = '이동 오류'
  3155. data = '이동 하려는 곳에 문서가 이미 있습니다.'
  3156. elif(num == 20):
  3157. title = '비밀번호 오류'
  3158. data = '재 확인이랑 비밀번호가 다릅니다.'
  3159. if(title):
  3160. return(
  3161. html_minify(
  3162. template(
  3163. 'index',
  3164. imp = [title, wiki_set(1), wiki_set(3), login_check(), custom_css(), custom_js(), 0, 0],
  3165. data = data,
  3166. menu = 0
  3167. )
  3168. )
  3169. )
  3170. else:
  3171. return(redirect('/'))
  3172. @error(404)
  3173. def error_404(error):
  3174. try:
  3175. return(redirect('/w/' + url_pas(wiki_set(2))))
  3176. except:
  3177. return(redirect('/setup'))
  3178. @error(500)
  3179. def error_500(error):
  3180. try:
  3181. curs.execute("select title from data limit 1", [that])
  3182. return(error)
  3183. except:
  3184. return(redirect('/setup'))
  3185. run(
  3186. app = app,
  3187. server = 'tornado',
  3188. host = '0.0.0.0',
  3189. port = int(set_data['port'])
  3190. )