Add most necessary files for admin interface.
darkmorford -
c1e4c31f199d
Not Reviewed
Show More
Add another comment
TODOs: 0 unresolved 0 Resolved
COMMENTS: 0 General 0 Inline
@@ -0,0 +1,3
1 RewriteEngine On
2
3 RewriteRule ^(.*)\.xml$ rss-$1.php
This diff has been collapsed as it changes many lines, (1465 lines changed) Show them Hide them
@@ -0,0 +1,1465
1 // ===================================================================
2 // Author: Matt Kruse <matt@mattkruse.com>
3 // WWW: http://www.mattkruse.com/
4 //
5 // NOTICE: You may use this code for any purpose, commercial or
6 // private, without any further permission from the author. You may
7 // remove this notice from your final code if you wish, however it is
8 // appreciated by the author if at least my web site address is kept.
9 //
10 // You may *NOT* re-distribute this code in any way except through its
11 // use. That means, you can include it in your product, or your web
12 // site, or any other form where the code is actually being used. You
13 // may not put the plain javascript up on your site for download or
14 // include it in your javascript libraries for download.
15 // If you wish to share this code with others, please just point them
16 // to the URL instead.
17 // Please DO NOT link directly to my .js files from your site. Copy
18 // the files to your server and use them there. Thank you.
19 // ===================================================================
20
21
22 /* SOURCE FILE: AnchorPosition.js */
23
24 /*
25 AnchorPosition.js
26 Author: Matt Kruse
27 Last modified: 10/11/02
28
29 DESCRIPTION: These functions find the position of an <A> tag in a document,
30 so other elements can be positioned relative to it.
31
32 COMPATABILITY: Netscape 4.x,6.x,Mozilla, IE 5.x,6.x on Windows. Some small
33 positioning errors - usually with Window positioning - occur on the
34 Macintosh platform.
35
36 FUNCTIONS:
37 getAnchorPosition(anchorname)
38 Returns an Object() having .x and .y properties of the pixel coordinates
39 of the upper-left corner of the anchor. Position is relative to the PAGE.
40
41 getAnchorWindowPosition(anchorname)
42 Returns an Object() having .x and .y properties of the pixel coordinates
43 of the upper-left corner of the anchor, relative to the WHOLE SCREEN.
44
45 NOTES:
46
47 1) For popping up separate browser windows, use getAnchorWindowPosition.
48 Otherwise, use getAnchorPosition
49
50 2) Your anchor tag MUST contain both NAME and ID attributes which are the
51 same. For example:
52 <A NAME="test" ID="test"> </A>
53
54 3) There must be at least a space between <A> </A> for IE5.5 to see the
55 anchor tag correctly. Do not do <A></A> with no space.
56 */
57
58 // getAnchorPosition(anchorname)
59 // This function returns an object having .x and .y properties which are the coordinates
60 // of the named anchor, relative to the page.
61 function getAnchorPosition(anchorname) {
62 // This function will return an Object with x and y properties
63 var useWindow=false;
64 var coordinates=new Object();
65 var x=0,y=0;
66 // Browser capability sniffing
67 var use_gebi=false, use_css=false, use_layers=false;
68 if (document.getElementById) { use_gebi=true; }
69 else if (document.all) { use_css=true; }
70 else if (document.layers) { use_layers=true; }
71 // Logic to find position
72 if (use_gebi && document.all) {
73 x=AnchorPosition_getPageOffsetLeft(document.all[anchorname]);
74 y=AnchorPosition_getPageOffsetTop(document.all[anchorname]);
75 }
76 else if (use_gebi) {
77 var o=document.getElementById(anchorname);
78 x=AnchorPosition_getPageOffsetLeft(o);
79 y=AnchorPosition_getPageOffsetTop(o);
80 }
81 else if (use_css) {
82 x=AnchorPosition_getPageOffsetLeft(document.all[anchorname]);
83 y=AnchorPosition_getPageOffsetTop(document.all[anchorname]);
84 }
85 else if (use_layers) {
86 var found=0;
87 for (var i=0; i<document.anchors.length; i++) {
88 if (document.anchors[i].name==anchorname) { found=1; break; }
89 }
90 if (found==0) {
91 coordinates.x=0; coordinates.y=0; return coordinates;
92 }
93 x=document.anchors[i].x;
94 y=document.anchors[i].y;
95 }
96 else {
97 coordinates.x=0; coordinates.y=0; return coordinates;
98 }
99 coordinates.x=x;
100 coordinates.y=y;
101 return coordinates;
102 }
103
104 // getAnchorWindowPosition(anchorname)
105 // This function returns an object having .x and .y properties which are the coordinates
106 // of the named anchor, relative to the window
107 function getAnchorWindowPosition(anchorname) {
108 var coordinates=getAnchorPosition(anchorname);
109 var x=0;
110 var y=0;
111 if (document.getElementById) {
112 if (isNaN(window.screenX)) {
113 x=coordinates.x-document.body.scrollLeft+window.screenLeft;
114 y=coordinates.y-document.body.scrollTop+window.screenTop;
115 }
116 else {
117 x=coordinates.x+window.screenX+(window.outerWidth-window.innerWidth)-window.pageXOffset;
118 y=coordinates.y+window.screenY+(window.outerHeight-24-window.innerHeight)-window.pageYOffset;
119 }
120 }
121 else if (document.all) {
122 x=coordinates.x-document.body.scrollLeft+window.screenLeft;
123 y=coordinates.y-document.body.scrollTop+window.screenTop;
124 }
125 else if (document.layers) {
126 x=coordinates.x+window.screenX+(window.outerWidth-window.innerWidth)-window.pageXOffset;
127 y=coordinates.y+window.screenY+(window.outerHeight-24-window.innerHeight)-window.pageYOffset;
128 }
129 coordinates.x=x;
130 coordinates.y=y;
131 return coordinates;
132 }
133
134 // Functions for IE to get position of an object
135 function AnchorPosition_getPageOffsetLeft (el) {
136 var ol=el.offsetLeft;
137 while ((el=el.offsetParent) != null) { ol += el.offsetLeft; }
138 return ol;
139 }
140 function AnchorPosition_getWindowOffsetLeft (el) {
141 return AnchorPosition_getPageOffsetLeft(el)-document.body.scrollLeft;
142 }
143 function AnchorPosition_getPageOffsetTop (el) {
144 var ot=el.offsetTop;
145 while((el=el.offsetParent) != null) { ot += el.offsetTop; }
146 return ot;
147 }
148 function AnchorPosition_getWindowOffsetTop (el) {
149 return AnchorPosition_getPageOffsetTop(el)-document.body.scrollTop;
150 }
151
152 /* SOURCE FILE: date.js */
153
154 // HISTORY
155 // ------------------------------------------------------------------
156 // May 17, 2003: Fixed bug in parseDate() for dates <1970
157 // March 11, 2003: Added parseDate() function
158 // March 11, 2003: Added "NNN" formatting option. Doesn't match up
159 // perfectly with SimpleDateFormat formats, but
160 // backwards-compatability was required.
161
162 // ------------------------------------------------------------------
163 // These functions use the same 'format' strings as the
164 // java.text.SimpleDateFormat class, with minor exceptions.
165 // The format string consists of the following abbreviations:
166 //
167 // Field | Full Form | Short Form
168 // -------------+--------------------+-----------------------
169 // Year | yyyy (4 digits) | yy (2 digits), y (2 or 4 digits)
170 // Month | MMM (name or abbr.)| MM (2 digits), M (1 or 2 digits)
171 // | NNN (abbr.) |
172 // Day of Month | dd (2 digits) | d (1 or 2 digits)
173 // Day of Week | EE (name) | E (abbr)
174 // Hour (1-12) | hh (2 digits) | h (1 or 2 digits)
175 // Hour (0-23) | HH (2 digits) | H (1 or 2 digits)
176 // Hour (0-11) | KK (2 digits) | K (1 or 2 digits)
177 // Hour (1-24) | kk (2 digits) | k (1 or 2 digits)
178 // Minute | mm (2 digits) | m (1 or 2 digits)
179 // Second | ss (2 digits) | s (1 or 2 digits)
180 // AM/PM | a |
181 //
182 // NOTE THE DIFFERENCE BETWEEN MM and mm! Month=MM, not mm!
183 // Examples:
184 // "MMM d, y" matches: January 01, 2000
185 // Dec 1, 1900
186 // Nov 20, 00
187 // "M/d/yy" matches: 01/20/00
188 // 9/2/00
189 // "MMM dd, yyyy hh:mm:ssa" matches: "January 01, 2000 12:30:45AM"
190 // ------------------------------------------------------------------
191
192 var MONTH_NAMES=new Array('January','February','March','April','May','June','July','August','September','October','November','December','Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
193 var DAY_NAMES=new Array('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sun','Mon','Tue','Wed','Thu','Fri','Sat');
194 function LZ(x) {return(x<0||x>9?"":"0")+x}
195
196 // ------------------------------------------------------------------
197 // isDate ( date_string, format_string )
198 // Returns true if date string matches format of format string and
199 // is a valid date. Else returns false.
200 // It is recommended that you trim whitespace around the value before
201 // passing it to this function, as whitespace is NOT ignored!
202 // ------------------------------------------------------------------
203 function isDate(val,format) {
204 var date=getDateFromFormat(val,format);
205 if (date==0) { return false; }
206 return true;
207 }
208
209 // -------------------------------------------------------------------
210 // compareDates(date1,date1format,date2,date2format)
211 // Compare two date strings to see which is greater.
212 // Returns:
213 // 1 if date1 is greater than date2
214 // 0 if date2 is greater than date1 of if they are the same
215 // -1 if either of the dates is in an invalid format
216 // -------------------------------------------------------------------
217 function compareDates(date1,dateformat1,date2,dateformat2) {
218 var d1=getDateFromFormat(date1,dateformat1);
219 var d2=getDateFromFormat(date2,dateformat2);
220 if (d1==0 || d2==0) {
221 return -1;
222 }
223 else if (d1 > d2) {
224 return 1;
225 }
226 return 0;
227 }
228
229 // ------------------------------------------------------------------
230 // formatDate (date_object, format)
231 // Returns a date in the output format specified.
232 // The format string uses the same abbreviations as in getDateFromFormat()
233 // ------------------------------------------------------------------
234 function formatDate(date,format) {
235 format=format+"";
236 var result="";
237 var i_format=0;
238 var c="";
239 var token="";
240 var y=date.getYear()+"";
241 var M=date.getMonth()+1;
242 var d=date.getDate();
243 var E=date.getDay();
244 var H=date.getHours();
245 var m=date.getMinutes();
246 var s=date.getSeconds();
247 var yyyy,yy,MMM,MM,dd,hh,h,mm,ss,ampm,HH,H,KK,K,kk,k;
248 // Convert real date parts into formatted versions
249 var value=new Object();
250 if (y.length < 4) {y=""+(y-0+1900);}
251 value["y"]=""+y;
252 value["yyyy"]=y;
253 value["yy"]=y.substring(2,4);
254 value["M"]=M;
255 value["MM"]=LZ(M);
256 value["MMM"]=MONTH_NAMES[M-1];
257 value["NNN"]=MONTH_NAMES[M+11];
258 value["d"]=d;
259 value["dd"]=LZ(d);
260 value["E"]=DAY_NAMES[E+7];
261 value["EE"]=DAY_NAMES[E];
262 value["H"]=H;
263 value["HH"]=LZ(H);
264 if (H==0){value["h"]=12;}
265 else if (H>12){value["h"]=H-12;}
266 else {value["h"]=H;}
267 value["hh"]=LZ(value["h"]);
268 if (H>11){value["K"]=H-12;} else {value["K"]=H;}
269 value["k"]=H+1;
270 value["KK"]=LZ(value["K"]);
271 value["kk"]=LZ(value["k"]);
272 if (H > 11) { value["a"]="PM"; }
273 else { value["a"]="AM"; }
274 value["m"]=m;
275 value["mm"]=LZ(m);
276 value["s"]=s;
277 value["ss"]=LZ(s);
278 while (i_format < format.length) {
279 c=format.charAt(i_format);
280 token="";
281 while ((format.charAt(i_format)==c) && (i_format < format.length)) {
282 token += format.charAt(i_format++);
283 }
284 if (value[token] != null) { result=result + value[token]; }
285 else { result=result + token; }
286 }
287 return result;
288 }
289
290 // ------------------------------------------------------------------
291 // Utility functions for parsing in getDateFromFormat()
292 // ------------------------------------------------------------------
293 function _isInteger(val) {
294 var digits="1234567890";
295 for (var i=0; i < val.length; i++) {
296 if (digits.indexOf(val.charAt(i))==-1) { return false; }
297 }
298 return true;
299 }
300 function _getInt(str,i,minlength,maxlength) {
301 for (var x=maxlength; x>=minlength; x--) {
302 var token=str.substring(i,i+x);
303 if (token.length < minlength) { return null; }
304 if (_isInteger(token)) { return token; }
305 }
306 return null;
307 }
308
309 // ------------------------------------------------------------------
310 // getDateFromFormat( date_string , format_string )
311 //
312 // This function takes a date string and a format string. It matches
313 // If the date string matches the format string, it returns the
314 // getTime() of the date. If it does not match, it returns 0.
315 // ------------------------------------------------------------------
316 function getDateFromFormat(val,format) {
317 val=val+"";
318 format=format+"";
319 var i_val=0;
320 var i_format=0;
321 var c="";
322 var token="";
323 var token2="";
324 var x,y;
325 var now=new Date();
326 var year=now.getYear();
327 var month=now.getMonth()+1;
328 var date=1;
329 var hh=now.getHours();
330 var mm=now.getMinutes();
331 var ss=now.getSeconds();
332 var ampm="";
333
334 while (i_format < format.length) {
335 // Get next token from format string
336 c=format.charAt(i_format);
337 token="";
338 while ((format.charAt(i_format)==c) && (i_format < format.length)) {
339 token += format.charAt(i_format++);
340 }
341 // Extract contents of value based on format token
342 if (token=="yyyy" || token=="yy" || token=="y") {
343 if (token=="yyyy") { x=4;y=4; }
344 if (token=="yy") { x=2;y=2; }
345 if (token=="y") { x=2;y=4; }
346 year=_getInt(val,i_val,x,y);
347 if (year==null) { return 0; }
348 i_val += year.length;
349 if (year.length==2) {
350 if (year > 70) { year=1900+(year-0); }
351 else { year=2000+(year-0); }
352 }
353 }
354 else if (token=="MMM"||token=="NNN"){
355 month=0;
356 for (var i=0; i<MONTH_NAMES.length; i++) {
357 var month_name=MONTH_NAMES[i];
358 if (val.substring(i_val,i_val+month_name.length).toLowerCase()==month_name.toLowerCase()) {
359 if (token=="MMM"||(token=="NNN"&&i>11)) {
360 month=i+1;
361 if (month>12) { month -= 12; }
362 i_val += month_name.length;
363 break;
364 }
365 }
366 }
367 if ((month < 1)||(month>12)){return 0;}
368 }
369 else if (token=="EE"||token=="E"){
370 for (var i=0; i<DAY_NAMES.length; i++) {
371 var day_name=DAY_NAMES[i];
372 if (val.substring(i_val,i_val+day_name.length).toLowerCase()==day_name.toLowerCase()) {
373 i_val += day_name.length;
374 break;
375 }
376 }
377 }
378 else if (token=="MM"||token=="M") {
379 month=_getInt(val,i_val,token.length,2);
380 if(month==null||(month<1)||(month>12)){return 0;}
381 i_val+=month.length;}
382 else if (token=="dd"||token=="d") {
383 date=_getInt(val,i_val,token.length,2);
384 if(date==null||(date<1)||(date>31)){return 0;}
385 i_val+=date.length;}
386 else if (token=="hh"||token=="h") {
387 hh=_getInt(val,i_val,token.length,2);
388 if(hh==null||(hh<1)||(hh>12)){return 0;}
389 i_val+=hh.length;}
390 else if (token=="HH"||token=="H") {
391 hh=_getInt(val,i_val,token.length,2);
392 if(hh==null||(hh<0)||(hh>23)){return 0;}
393 i_val+=hh.length;}
394 else if (token=="KK"||token=="K") {
395 hh=_getInt(val,i_val,token.length,2);
396 if(hh==null||(hh<0)||(hh>11)){return 0;}
397 i_val+=hh.length;}
398 else if (token=="kk"||token=="k") {
399 hh=_getInt(val,i_val,token.length,2);
400 if(hh==null||(hh<1)||(hh>24)){return 0;}
401 i_val+=hh.length;hh--;}
402 else if (token=="mm"||token=="m") {
403 mm=_getInt(val,i_val,token.length,2);
404 if(mm==null||(mm<0)||(mm>59)){return 0;}
405 i_val+=mm.length;}
406 else if (token=="ss"||token=="s") {
407 ss=_getInt(val,i_val,token.length,2);
408 if(ss==null||(ss<0)||(ss>59)){return 0;}
409 i_val+=ss.length;}
410 else if (token=="a") {
411 if (val.substring(i_val,i_val+2).toLowerCase()=="am") {ampm="AM";}
412 else if (val.substring(i_val,i_val+2).toLowerCase()=="pm") {ampm="PM";}
413 else {return 0;}
414 i_val+=2;}
415 else {
416 if (val.substring(i_val,i_val+token.length)!=token) {return 0;}
417 else {i_val+=token.length;}
418 }
419 }
420 // If there are any trailing characters left in the value, it doesn't match
421 if (i_val != val.length) { return 0; }
422 // Is date valid for month?
423 if (month==2) {
424 // Check for leap year
425 if ( ( (year%4==0)&&(year%100 != 0) ) || (year%400==0) ) { // leap year
426 if (date > 29){ return 0; }
427 }
428 else { if (date > 28) { return 0; } }
429 }
430 if ((month==4)||(month==6)||(month==9)||(month==11)) {
431 if (date > 30) { return 0; }
432 }
433 // Correct hours value
434 if (hh<12 && ampm=="PM") { hh=hh-0+12; }
435 else if (hh>11 && ampm=="AM") { hh-=12; }
436 var newdate=new Date(year,month-1,date,hh,mm,ss);
437 return newdate.getTime();
438 }
439
440 // ------------------------------------------------------------------
441 // parseDate( date_string [, prefer_euro_format] )
442 //
443 // This function takes a date string and tries to match it to a
444 // number of possible date formats to get the value. It will try to
445 // match against the following international formats, in this order:
446 // y-M-d MMM d, y MMM d,y y-MMM-d d-MMM-y MMM d
447 // M/d/y M-d-y M.d.y MMM-d M/d M-d
448 // d/M/y d-M-y d.M.y d-MMM d/M d-M
449 // A second argument may be passed to instruct the method to search
450 // for formats like d/M/y (european format) before M/d/y (American).
451 // Returns a Date object or null if no patterns match.
452 // ------------------------------------------------------------------
453 function parseDate(val) {
454 var preferEuro=(arguments.length==2)?arguments[1]:false;
455 generalFormats=new Array('y-M-d','MMM d, y','MMM d,y','y-MMM-d','d-MMM-y','MMM d');
456 monthFirst=new Array('M/d/y','M-d-y','M.d.y','MMM-d','M/d','M-d');
457 dateFirst =new Array('d/M/y','d-M-y','d.M.y','d-MMM','d/M','d-M');
458 var checkList=new Array('generalFormats',preferEuro?'dateFirst':'monthFirst',preferEuro?'monthFirst':'dateFirst');
459 var d=null;
460 for (var i=0; i<checkList.length; i++) {
461 var l=window[checkList[i]];
462 for (var j=0; j<l.length; j++) {
463 d=getDateFromFormat(val,l[j]);
464 if (d!=0) { return new Date(d); }
465 }
466 }
467 return null;
468 }
469
470 /* SOURCE FILE: PopupWindow.js */
471
472 /*
473 PopupWindow.js
474 Author: Matt Kruse
475 Last modified: 02/16/04
476
477 DESCRIPTION: This object allows you to easily and quickly popup a window
478 in a certain place. The window can either be a DIV or a separate browser
479 window.
480
481 COMPATABILITY: Works with Netscape 4.x, 6.x, IE 5.x on Windows. Some small
482 positioning errors - usually with Window positioning - occur on the
483 Macintosh platform. Due to bugs in Netscape 4.x, populating the popup
484 window with <STYLE> tags may cause errors.
485
486 USAGE:
487 // Create an object for a WINDOW popup
488 var win = new PopupWindow();
489
490 // Create an object for a DIV window using the DIV named 'mydiv'
491 var win = new PopupWindow('mydiv');
492
493 // Set the window to automatically hide itself when the user clicks
494 // anywhere else on the page except the popup
495 win.autoHide();
496
497 // Show the window relative to the anchor name passed in
498 win.showPopup(anchorname);
499
500 // Hide the popup
501 win.hidePopup();
502
503 // Set the size of the popup window (only applies to WINDOW popups
504 win.setSize(width,height);
505
506 // Populate the contents of the popup window that will be shown. If you
507 // change the contents while it is displayed, you will need to refresh()
508 win.populate(string);
509
510 // set the URL of the window, rather than populating its contents
511 // manually
512 win.setUrl("http://www.site.com/");
513
514 // Refresh the contents of the popup
515 win.refresh();
516
517 // Specify how many pixels to the right of the anchor the popup will appear
518 win.offsetX = 50;
519
520 // Specify how many pixels below the anchor the popup will appear
521 win.offsetY = 100;
522
523 NOTES:
524 1) Requires the functions in AnchorPosition.js
525
526 2) Your anchor tag MUST contain both NAME and ID attributes which are the
527 same. For example:
528 <A NAME="test" ID="test"> </A>
529
530 3) There must be at least a space between <A> </A> for IE5.5 to see the
531 anchor tag correctly. Do not do <A></A> with no space.
532
533 4) When a PopupWindow object is created, a handler for 'onmouseup' is
534 attached to any event handler you may have already defined. Do NOT define
535 an event handler for 'onmouseup' after you define a PopupWindow object or
536 the autoHide() will not work correctly.
537 */
538
539 // Set the position of the popup window based on the anchor
540 function PopupWindow_getXYPosition(anchorname) {
541 var coordinates;
542 if (this.type == "WINDOW") {
543 coordinates = getAnchorWindowPosition(anchorname);
544 }
545 else {
546 coordinates = getAnchorPosition(anchorname);
547 }
548 this.x = coordinates.x;
549 this.y = coordinates.y;
550 }
551 // Set width/height of DIV/popup window
552 function PopupWindow_setSize(width,height) {
553 this.width = width;
554 this.height = height;
555 }
556 // Fill the window with contents
557 function PopupWindow_populate(contents) {
558 this.contents = contents;
559 this.populated = false;
560 }
561 // Set the URL to go to
562 function PopupWindow_setUrl(url) {
563 this.url = url;
564 }
565 // Set the window popup properties
566 function PopupWindow_setWindowProperties(props) {
567 this.windowProperties = props;
568 }
569 // Refresh the displayed contents of the popup
570 function PopupWindow_refresh() {
571 if (this.divName != null) {
572 // refresh the DIV object
573 if (this.use_gebi) {
574 document.getElementById(this.divName).innerHTML = this.contents;
575 }
576 else if (this.use_css) {
577 document.all[this.divName].innerHTML = this.contents;
578 }
579 else if (this.use_layers) {
580 var d = document.layers[this.divName];
581 d.document.open();
582 d.document.writeln(this.contents);
583 d.document.close();
584 }
585 }
586 else {
587 if (this.popupWindow != null && !this.popupWindow.closed) {
588 if (this.url!="") {
589 this.popupWindow.location.href=this.url;
590 }
591 else {
592 this.popupWindow.document.open();
593 this.popupWindow.document.writeln(this.contents);
594 this.popupWindow.document.close();
595 }
596 this.popupWindow.focus();
597 }
598 }
599 }
600 // Position and show the popup, relative to an anchor object
601 function PopupWindow_showPopup(anchorname) {
602 this.getXYPosition(anchorname);
603 this.x += this.offsetX;
604 this.y += this.offsetY;
605 if (!this.populated && (this.contents != "")) {
606 this.populated = true;
607 this.refresh();
608 }
609 if (this.divName != null) {
610 // Show the DIV object
611 if (this.use_gebi) {
612 document.getElementById(this.divName).style.left = this.x + "px";
613 document.getElementById(this.divName).style.top = this.y + "px";
614 document.getElementById(this.divName).style.visibility = "visible";
615 }
616 else if (this.use_css) {
617 document.all[this.divName].style.left = this.x;
618 document.all[this.divName].style.top = this.y;
619 document.all[this.divName].style.visibility = "visible";
620 }
621 else if (this.use_layers) {
622 document.layers[this.divName].left = this.x;
623 document.layers[this.divName].top = this.y;
624 document.layers[this.divName].visibility = "visible";
625 }
626 }
627 else {
628 if (this.popupWindow == null || this.popupWindow.closed) {
629 // If the popup window will go off-screen, move it so it doesn't
630 if (this.x<0) { this.x=0; }
631 if (this.y<0) { this.y=0; }
632 if (screen && screen.availHeight) {
633 if ((this.y + this.height) > screen.availHeight) {
634 this.y = screen.availHeight - this.height;
635 }
636 }
637 if (screen && screen.availWidth) {
638 if ((this.x + this.width) > screen.availWidth) {
639 this.x = screen.availWidth - this.width;
640 }
641 }
642 var avoidAboutBlank = window.opera || ( document.layers && !navigator.mimeTypes['*'] ) || navigator.vendor == 'KDE' || ( document.childNodes && !document.all && !navigator.taintEnabled );
643 this.popupWindow = window.open(avoidAboutBlank?"":"about:blank","window_"+anchorname,this.windowProperties+",width="+this.width+",height="+this.height+",screenX="+this.x+",left="+this.x+",screenY="+this.y+",top="+this.y+"");
644 }
645 this.refresh();
646 }
647 }
648 // Hide the popup
649 function PopupWindow_hidePopup() {
650 if (this.divName != null) {
651 if (this.use_gebi) {
652 document.getElementById(this.divName).style.visibility = "hidden";
653 }
654 else if (this.use_css) {
655 document.all[this.divName].style.visibility = "hidden";
656 }
657 else if (this.use_layers) {
658 document.layers[this.divName].visibility = "hidden";
659 }
660 }
661 else {
662 if (this.popupWindow && !this.popupWindow.closed) {
663 this.popupWindow.close();
664 this.popupWindow = null;
665 }
666 }
667 }
668 // Pass an event and return whether or not it was the popup DIV that was clicked
669 function PopupWindow_isClicked(e) {
670 if (this.divName != null) {
671 if (this.use_layers) {
672 var clickX = e.pageX;
673 var clickY = e.pageY;
674 var t = document.layers[this.divName];
675 if ((clickX > t.left) && (clickX < t.left+t.clip.width) && (clickY > t.top) && (clickY < t.top+t.clip.height)) {
676 return true;
677 }
678 else { return false; }
679 }
680 else if (document.all) { // Need to hard-code this to trap IE for error-handling
681 var t = window.event.srcElement;
682 while (t.parentElement != null) {
683 if (t.id==this.divName) {
684 return true;
685 }
686 t = t.parentElement;
687 }
688 return false;
689 }
690 else if (this.use_gebi && e) {
691 var t = e.originalTarget;
692 while (t.parentNode != null) {
693 if (t.id==this.divName) {
694 return true;
695 }
696 t = t.parentNode;
697 }
698 return false;
699 }
700 return false;
701 }
702 return false;
703 }
704
705 // Check an onMouseDown event to see if we should hide
706 function PopupWindow_hideIfNotClicked(e) {
707 if (this.autoHideEnabled && !this.isClicked(e)) {
708 this.hidePopup();
709 }
710 }
711 // Call this to make the DIV disable automatically when mouse is clicked outside it
712 function PopupWindow_autoHide() {
713 this.autoHideEnabled = true;
714 }
715 // This global function checks all PopupWindow objects onmouseup to see if they should be hidden
716 function PopupWindow_hidePopupWindows(e) {
717 for (var i=0; i<popupWindowObjects.length; i++) {
718 if (popupWindowObjects[i] != null) {
719 var p = popupWindowObjects[i];
720 p.hideIfNotClicked(e);
721 }
722 }
723 }
724 // Run this immediately to attach the event listener
725 function PopupWindow_attachListener() {
726 if (document.layers) {
727 document.captureEvents(Event.MOUSEUP);
728 }
729 window.popupWindowOldEventListener = document.onmouseup;
730 if (window.popupWindowOldEventListener != null) {
731 document.onmouseup = new Function("window.popupWindowOldEventListener(); PopupWindow_hidePopupWindows();");
732 }
733 else {
734 document.onmouseup = PopupWindow_hidePopupWindows;
735 }
736 }
737 // CONSTRUCTOR for the PopupWindow object
738 // Pass it a DIV name to use a DHTML popup, otherwise will default to window popup
739 function PopupWindow() {
740 if (!window.popupWindowIndex) { window.popupWindowIndex = 0; }
741 if (!window.popupWindowObjects) { window.popupWindowObjects = new Array(); }
742 if (!window.listenerAttached) {
743 window.listenerAttached = true;
744 PopupWindow_attachListener();
745 }
746 this.index = popupWindowIndex++;
747 popupWindowObjects[this.index] = this;
748 this.divName = null;
749 this.popupWindow = null;
750 this.width=0;
751 this.height=0;
752 this.populated = false;
753 this.visible = false;
754 this.autoHideEnabled = false;
755
756 this.contents = "";
757 this.url="";
758 this.windowProperties="toolbar=no,location=no,status=no,menubar=no,scrollbars=auto,resizable,alwaysRaised,dependent,titlebar=no";
759 if (arguments.length>0) {
760 this.type="DIV";
761 this.divName = arguments[0];
762 }
763 else {
764 this.type="WINDOW";
765 }
766 this.use_gebi = false;
767 this.use_css = false;
768 this.use_layers = false;
769 if (document.getElementById) { this.use_gebi = true; }
770 else if (document.all) { this.use_css = true; }
771 else if (document.layers) { this.use_layers = true; }
772 else { this.type = "WINDOW"; }
773 this.offsetX = 0;
774 this.offsetY = 0;
775 // Method mappings
776 this.getXYPosition = PopupWindow_getXYPosition;
777 this.populate = PopupWindow_populate;
778 this.setUrl = PopupWindow_setUrl;
779 this.setWindowProperties = PopupWindow_setWindowProperties;
780 this.refresh = PopupWindow_refresh;
781 this.showPopup = PopupWindow_showPopup;
782 this.hidePopup = PopupWindow_hidePopup;
783 this.setSize = PopupWindow_setSize;
784 this.isClicked = PopupWindow_isClicked;
785 this.autoHide = PopupWindow_autoHide;
786 this.hideIfNotClicked = PopupWindow_hideIfNotClicked;
787 }
788
789 /* SOURCE FILE: CalendarPopup.js */
790
791 // HISTORY
792 // ------------------------------------------------------------------
793 // Feb 7, 2005: Fixed a CSS styles to use px unit
794 // March 29, 2004: Added check in select() method for the form field
795 // being disabled. If it is, just return and don't do anything.
796 // March 24, 2004: Fixed bug - when month name and abbreviations were
797 // changed, date format still used original values.
798 // January 26, 2004: Added support for drop-down month and year
799 // navigation (Thanks to Chris Reid for the idea)
800 // September 22, 2003: Fixed a minor problem in YEAR calendar with
801 // CSS prefix.
802 // August 19, 2003: Renamed the function to get styles, and made it
803 // work correctly without an object reference
804 // August 18, 2003: Changed showYearNavigation and
805 // showYearNavigationInput to optionally take an argument of
806 // true or false
807 // July 31, 2003: Added text input option for year navigation.
808 // Added a per-calendar CSS prefix option to optionally use
809 // different styles for different calendars.
810 // July 29, 2003: Fixed bug causing the Today link to be clickable
811 // even though today falls in a disabled date range.
812 // Changed formatting to use pure CSS, allowing greater control
813 // over look-and-feel options.
814 // June 11, 2003: Fixed bug causing the Today link to be unselectable
815 // under certain cases when some days of week are disabled
816 // March 14, 2003: Added ability to disable individual dates or date
817 // ranges, display as light gray and strike-through
818 // March 14, 2003: Removed dependency on graypixel.gif and instead
819 /// use table border coloring
820 // March 12, 2003: Modified showCalendar() function to allow optional
821 // start-date parameter
822 // March 11, 2003: Modified select() function to allow optional
823 // start-date parameter
824 /*
825 DESCRIPTION: This object implements a popup calendar to allow the user to
826 select a date, month, quarter, or year.
827
828 COMPATABILITY: Works with Netscape 4.x, 6.x, IE 5.x on Windows. Some small
829 positioning errors - usually with Window positioning - occur on the
830 Macintosh platform.
831 The calendar can be modified to work for any location in the world by
832 changing which weekday is displayed as the first column, changing the month
833 names, and changing the column headers for each day.
834
835 USAGE:
836 // Create a new CalendarPopup object of type WINDOW
837 var cal = new CalendarPopup();
838
839 // Create a new CalendarPopup object of type DIV using the DIV named 'mydiv'
840 var cal = new CalendarPopup('mydiv');
841
842 // Easy method to link the popup calendar with an input box.
843 cal.select(inputObject, anchorname, dateFormat);
844 // Same method, but passing a default date other than the field's current value
845 cal.select(inputObject, anchorname, dateFormat, '01/02/2000');
846 // This is an example call to the popup calendar from a link to populate an
847 // input box. Note that to use this, date.js must also be included!!
848 <A HREF="#" onClick="cal.select(document.forms[0].date,'anchorname','MM/dd/yyyy'); return false;">Select</A>
849
850 // Set the type of date select to be used. By default it is 'date'.
851 cal.setDisplayType(type);
852
853 // When a date, month, quarter, or year is clicked, a function is called and
854 // passed the details. You must write this function, and tell the calendar
855 // popup what the function name is.
856 // Function to be called for 'date' select receives y, m, d
857 cal.setReturnFunction(functionname);
858 // Function to be called for 'month' select receives y, m
859 cal.setReturnMonthFunction(functionname);
860 // Function to be called for 'quarter' select receives y, q
861 cal.setReturnQuarterFunction(functionname);
862 // Function to be called for 'year' select receives y
863 cal.setReturnYearFunction(functionname);
864
865 // Show the calendar relative to a given anchor
866 cal.showCalendar(anchorname);
867
868 // Hide the calendar. The calendar is set to autoHide automatically
869 cal.hideCalendar();
870
871 // Set the month names to be used. Default are English month names
872 cal.setMonthNames("January","February","March",...);
873
874 // Set the month abbreviations to be used. Default are English month abbreviations
875 cal.setMonthAbbreviations("Jan","Feb","Mar",...);
876
877 // Show navigation for changing by the year, not just one month at a time
878 cal.showYearNavigation();
879
880 // Show month and year dropdowns, for quicker selection of month of dates
881 cal.showNavigationDropdowns();
882
883 // Set the text to be used above each day column. The days start with
884 // sunday regardless of the value of WeekStartDay
885 cal.setDayHeaders("S","M","T",...);
886
887 // Set the day for the first column in the calendar grid. By default this
888 // is Sunday (0) but it may be changed to fit the conventions of other
889 // countries.
890 cal.setWeekStartDay(1); // week is Monday - Sunday
891
892 // Set the weekdays which should be disabled in the 'date' select popup. You can
893 // then allow someone to only select week end dates, or Tuedays, for example
894 cal.setDisabledWeekDays(0,1); // To disable selecting the 1st or 2nd days of the week
895
896 // Selectively disable individual days or date ranges. Disabled days will not
897 // be clickable, and show as strike-through text on current browsers.
898 // Date format is any format recognized by parseDate() in date.js
899 // Pass a single date to disable:
900 cal.addDisabledDates("2003-01-01");
901 // Pass null as the first parameter to mean "anything up to and including" the
902 // passed date:
903 cal.addDisabledDates(null, "01/02/03");
904 // Pass null as the second parameter to mean "including the passed date and
905 // anything after it:
906 cal.addDisabledDates("Jan 01, 2003", null);
907 // Pass two dates to disable all dates inbetween and including the two
908 cal.addDisabledDates("January 01, 2003", "Dec 31, 2003");
909
910 // When the 'year' select is displayed, set the number of years back from the
911 // current year to start listing years. Default is 2.
912 // This is also used for year drop-down, to decide how many years +/- to display
913 cal.setYearSelectStartOffset(2);
914
915 // Text for the word "Today" appearing on the calendar
916 cal.setTodayText("Today");
917
918 // The calendar uses CSS classes for formatting. If you want your calendar to
919 // have unique styles, you can set the prefix that will be added to all the
920 // classes in the output.
921 // For example, normal output may have this:
922 // <SPAN CLASS="cpTodayTextDisabled">Today<SPAN>
923 // But if you set the prefix like this:
924 cal.setCssPrefix("Test");
925 // The output will then look like:
926 // <SPAN CLASS="TestcpTodayTextDisabled">Today<SPAN>
927 // And you can define that style somewhere in your page.
928
929 // When using Year navigation, you can make the year be an input box, so
930 // the user can manually change it and jump to any year
931 cal.showYearNavigationInput();
932
933 // Set the calendar offset to be different than the default. By default it
934 // will appear just below and to the right of the anchorname. So if you have
935 // a text box where the date will go and and anchor immediately after the
936 // text box, the calendar will display immediately under the text box.
937 cal.offsetX = 20;
938 cal.offsetY = 20;
939
940 NOTES:
941 1) Requires the functions in AnchorPosition.js and PopupWindow.js
942
943 2) Your anchor tag MUST contain both NAME and ID attributes which are the
944 same. For example:
945 <A NAME="test" ID="test"> </A>
946
947 3) There must be at least a space between <A> </A> for IE5.5 to see the
948 anchor tag correctly. Do not do <A></A> with no space.
949
950 4) When a CalendarPopup object is created, a handler for 'onmouseup' is
951 attached to any event handler you may have already defined. Do NOT define
952 an event handler for 'onmouseup' after you define a CalendarPopup object
953 or the autoHide() will not work correctly.
954
955 5) The calendar popup display uses style sheets to make it look nice.
956
957 */
958
959 // Quick fix for FF3
960 function CP_stop(e) { if (e && e.stopPropagation) { e.stopPropagation(); } }
961
962 // CONSTRUCTOR for the CalendarPopup Object
963 function CalendarPopup() {
964 var c;
965 if (arguments.length>0) {
966 c = new PopupWindow(arguments[0]);
967 }
968 else {
969 c = new PopupWindow();
970 c.setSize(150,175);
971 }
972 c.offsetX = -152;
973 c.offsetY = 25;
974 c.autoHide();
975 // Calendar-specific properties
976 c.monthNames = new Array("January","February","March","April","May","June","July","August","September","October","November","December");
977 c.monthAbbreviations = new Array("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec");
978 c.dayHeaders = new Array("S","M","T","W","T","F","S");
979 c.returnFunction = "CP_tmpReturnFunction";
980 c.returnMonthFunction = "CP_tmpReturnMonthFunction";
981 c.returnQuarterFunction = "CP_tmpReturnQuarterFunction";
982 c.returnYearFunction = "CP_tmpReturnYearFunction";
983 c.weekStartDay = 0;
984 c.isShowYearNavigation = false;
985 c.displayType = "date";
986 c.disabledWeekDays = new Object();
987 c.disabledDatesExpression = "";
988 c.yearSelectStartOffset = 2;
989 c.currentDate = null;
990 c.todayText="Today";
991 c.cssPrefix="";
992 c.isShowNavigationDropdowns=false;
993 c.isShowYearNavigationInput=false;
994 window.CP_calendarObject = null;
995 window.CP_targetInput = null;
996 window.CP_dateFormat = "MM/dd/yyyy";
997 // Method mappings
998 c.copyMonthNamesToWindow = CP_copyMonthNamesToWindow;
999 c.setReturnFunction = CP_setReturnFunction;
1000 c.setReturnMonthFunction = CP_setReturnMonthFunction;
1001 c.setReturnQuarterFunction = CP_setReturnQuarterFunction;
1002 c.setReturnYearFunction = CP_setReturnYearFunction;
1003 c.setMonthNames = CP_setMonthNames;
1004 c.setMonthAbbreviations = CP_setMonthAbbreviations;
1005 c.setDayHeaders = CP_setDayHeaders;
1006 c.setWeekStartDay = CP_setWeekStartDay;
1007 c.setDisplayType = CP_setDisplayType;
1008 c.setDisabledWeekDays = CP_setDisabledWeekDays;
1009 c.addDisabledDates = CP_addDisabledDates;
1010 c.setYearSelectStartOffset = CP_setYearSelectStartOffset;
1011 c.setTodayText = CP_setTodayText;
1012 c.showYearNavigation = CP_showYearNavigation;
1013 c.showCalendar = CP_showCalendar;
1014 c.hideCalendar = CP_hideCalendar;
1015 c.getStyles = getCalendarStyles;
1016 c.refreshCalendar = CP_refreshCalendar;
1017 c.getCalendar = CP_getCalendar;
1018 c.select = CP_select;
1019 c.setCssPrefix = CP_setCssPrefix;
1020 c.showNavigationDropdowns = CP_showNavigationDropdowns;
1021 c.showYearNavigationInput = CP_showYearNavigationInput;
1022 c.copyMonthNamesToWindow();
1023 // Return the object
1024 return c;
1025 }
1026 function CP_copyMonthNamesToWindow() {
1027 // Copy these values over to the date.js
1028 if (typeof(window.MONTH_NAMES)!="undefined" && window.MONTH_NAMES!=null) {
1029 window.MONTH_NAMES = new Array();
1030 for (var i=0; i<this.monthNames.length; i++) {
1031 window.MONTH_NAMES[window.MONTH_NAMES.length] = this.monthNames[i];
1032 }
1033 for (var i=0; i<this.monthAbbreviations.length; i++) {
1034 window.MONTH_NAMES[window.MONTH_NAMES.length] = this.monthAbbreviations[i];
1035 }
1036 }
1037 }
1038 // Temporary default functions to be called when items clicked, so no error is thrown
1039 function CP_tmpReturnFunction(y,m,d) {
1040 if (window.CP_targetInput!=null) {
1041 var dt = new Date(y,m-1,d,0,0,0);
1042 if (window.CP_calendarObject!=null) { window.CP_calendarObject.copyMonthNamesToWindow(); }
1043 window.CP_targetInput.value = formatDate(dt,window.CP_dateFormat);
1044 }
1045 else {
1046 alert('Use setReturnFunction() to define which function will get the clicked results!');
1047 }
1048 }
1049 function CP_tmpReturnMonthFunction(y,m) {
1050 alert('Use setReturnMonthFunction() to define which function will get the clicked results!\nYou clicked: year='+y+' , month='+m);
1051 }
1052 function CP_tmpReturnQuarterFunction(y,q) {
1053 alert('Use setReturnQuarterFunction() to define which function will get the clicked results!\nYou clicked: year='+y+' , quarter='+q);
1054 }
1055 function CP_tmpReturnYearFunction(y) {
1056 alert('Use setReturnYearFunction() to define which function will get the clicked results!\nYou clicked: year='+y);
1057 }
1058
1059 // Set the name of the functions to call to get the clicked item
1060 function CP_setReturnFunction(name) { this.returnFunction = name; }
1061 function CP_setReturnMonthFunction(name) { this.returnMonthFunction = name; }
1062 function CP_setReturnQuarterFunction(name) { this.returnQuarterFunction = name; }
1063 function CP_setReturnYearFunction(name) { this.returnYearFunction = name; }
1064
1065 // Over-ride the built-in month names
1066 function CP_setMonthNames() {
1067 for (var i=0; i<arguments.length; i++) { this.monthNames[i] = arguments[i]; }
1068 this.copyMonthNamesToWindow();
1069 }
1070
1071 // Over-ride the built-in month abbreviations
1072 function CP_setMonthAbbreviations() {
1073 for (var i=0; i<arguments.length; i++) { this.monthAbbreviations[i] = arguments[i]; }
1074 this.copyMonthNamesToWindow();
1075 }
1076
1077 // Over-ride the built-in column headers for each day
1078 function CP_setDayHeaders() {
1079 for (var i=0; i<arguments.length; i++) { this.dayHeaders[i] = arguments[i]; }
1080 }
1081
1082 // Set the day of the week (0-7) that the calendar display starts on
1083 // This is for countries other than the US whose calendar displays start on Monday(1), for example
1084 function CP_setWeekStartDay(day) { this.weekStartDay = day; }
1085
1086 // Show next/last year navigation links
1087 function CP_showYearNavigation() { this.isShowYearNavigation = (arguments.length>0)?arguments[0]:true; }
1088
1089 // Which type of calendar to display
1090 function CP_setDisplayType(type) {
1091 if (type!="date"&&type!="week-end"&&type!="month"&&type!="quarter"&&type!="year") { alert("Invalid display type! Must be one of: date,week-end,month,quarter,year"); return false; }
1092 this.displayType=type;
1093 }
1094
1095 // How many years back to start by default for year display
1096 function CP_setYearSelectStartOffset(num) { this.yearSelectStartOffset=num; }
1097
1098 // Set which weekdays should not be clickable
1099 function CP_setDisabledWeekDays() {
1100 this.disabledWeekDays = new Object();
1101 for (var i=0; i<arguments.length; i++) { this.disabledWeekDays[arguments[i]] = true; }
1102 }
1103
1104 // Disable individual dates or ranges
1105 // Builds an internal logical test which is run via eval() for efficiency
1106 function CP_addDisabledDates(start, end) {
1107 if (arguments.length==1) { end=start; }
1108 if (start==null && end==null) { return; }
1109 if (this.disabledDatesExpression!="") { this.disabledDatesExpression+= "||"; }
1110 if (start!=null) { start = parseDate(start); start=""+start.getFullYear()+LZ(start.getMonth()+1)+LZ(start.getDate());}
1111 if (end!=null) { end=parseDate(end); end=""+end.getFullYear()+LZ(end.getMonth()+1)+LZ(end.getDate());}
1112 if (start==null) { this.disabledDatesExpression+="(ds<="+end+")"; }
1113 else if (end ==null) { this.disabledDatesExpression+="(ds>="+start+")"; }
1114 else { this.disabledDatesExpression+="(ds>="+start+"&&ds<="+end+")"; }
1115 }
1116
1117 // Set the text to use for the "Today" link
1118 function CP_setTodayText(text) {
1119 this.todayText = text;
1120 }
1121
1122 // Set the prefix to be added to all CSS classes when writing output
1123 function CP_setCssPrefix(val) {
1124 this.cssPrefix = val;
1125 }
1126
1127 // Show the navigation as an dropdowns that can be manually changed
1128 function CP_showNavigationDropdowns() { this.isShowNavigationDropdowns = (arguments.length>0)?arguments[0]:true; }
1129
1130 // Show the year navigation as an input box that can be manually changed
1131 function CP_showYearNavigationInput() { this.isShowYearNavigationInput = (arguments.length>0)?arguments[0]:true; }
1132
1133 // Hide a calendar object
1134 function CP_hideCalendar() {
1135 if (arguments.length > 0) { window.popupWindowObjects[arguments[0]].hidePopup(); }
1136 else { this.hidePopup(); }
1137 }
1138
1139 // Refresh the contents of the calendar display
1140 function CP_refreshCalendar(index) {
1141 var calObject = window.popupWindowObjects[index];
1142 if (arguments.length>1) {
1143 calObject.populate(calObject.getCalendar(arguments[1],arguments[2],arguments[3],arguments[4],arguments[5]));
1144 }
1145 else {
1146 calObject.populate(calObject.getCalendar());
1147 }
1148 calObject.refresh();
1149 }
1150
1151 // Populate the calendar and display it
1152 function CP_showCalendar(anchorname) {
1153 if (arguments.length>1) {
1154 if (arguments[1]==null||arguments[1]=="") {
1155 this.currentDate=new Date();
1156 }
1157 else {
1158 this.currentDate=new Date(parseDate(arguments[1]));
1159 }
1160 }
1161 this.populate(this.getCalendar());
1162 this.showPopup(anchorname);
1163 }
1164
1165 // Simple method to interface popup calendar with a text-entry box
1166 function CP_select(inputobj, linkname, format) {
1167 var selectedDate=(arguments.length>3)?arguments[3]:null;
1168 if (!window.getDateFromFormat) {
1169 alert("calendar.select: To use this method you must also include 'date.js' for date formatting");
1170 return;
1171 }
1172 if (this.displayType!="date"&&this.displayType!="week-end") {
1173 alert("calendar.select: This function can only be used with displayType 'date' or 'week-end'");
1174 return;
1175 }
1176 if (inputobj.type!="text" && inputobj.type!="hidden" && inputobj.type!="textarea") {
1177 alert("calendar.select: Input object passed is not a valid form input object");
1178 window.CP_targetInput=null;
1179 return;
1180 }
1181 if (inputobj.disabled) { return; } // Can't use calendar input on disabled form input!
1182 window.CP_targetInput = inputobj;
1183 window.CP_calendarObject = this;
1184 this.currentDate=null;
1185 var time=0;
1186 if (selectedDate!=null) {
1187 time = getDateFromFormat(selectedDate,format)
1188 }
1189 else if (inputobj.value!="") {
1190 time = getDateFromFormat(inputobj.value,format);
1191 }
1192 if (selectedDate!=null || inputobj.value!="") {
1193 if (time==0) { this.currentDate=null; }
1194 else { this.currentDate=new Date(time); }
1195 }
1196 window.CP_dateFormat = format;
1197 this.showCalendar(linkname);
1198 }
1199
1200 // Get style block needed to display the calendar correctly
1201 function getCalendarStyles() {
1202 var result = "";
1203 var p = "";
1204 if (this!=null && typeof(this.cssPrefix)!="undefined" && this.cssPrefix!=null && this.cssPrefix!="") { p=this.cssPrefix; }
1205 result += "<STYLE>\n";
1206 result += "."+p+"cpYearNavigation,."+p+"cpMonthNavigation { background-color:#C0C0C0; text-align:center; vertical-align:center; text-decoration:none; color:#000000; font-weight:bold; }\n";
1207 result += "."+p+"cpDayColumnHeader, ."+p+"cpYearNavigation,."+p+"cpMonthNavigation,."+p+"cpCurrentMonthDate,."+p+"cpCurrentMonthDateDisabled,."+p+"cpOtherMonthDate,."+p+"cpOtherMonthDateDisabled,."+p+"cpCurrentDate,."+p+"cpCurrentDateDisabled,."+p+"cpTodayText,."+p+"cpTodayTextDisabled,."+p+"cpText { font-family:arial; font-size:8pt; }\n";
1208 result += "TD."+p+"cpDayColumnHeader { text-align:right; border:solid thin #C0C0C0;border-width:0px 0px 1px 0px; }\n";
1209 result += "."+p+"cpCurrentMonthDate, ."+p+"cpOtherMonthDate, ."+p+"cpCurrentDate { text-align:right; text-decoration:none; }\n";
1210 result += "."+p+"cpCurrentMonthDateDisabled, ."+p+"cpOtherMonthDateDisabled, ."+p+"cpCurrentDateDisabled { color:#D0D0D0; text-align:right; text-decoration:line-through; }\n";
1211 result += "."+p+"cpCurrentMonthDate, .cpCurrentDate { color:#000000; }\n";
1212 result += "."+p+"cpOtherMonthDate { color:#808080; }\n";
1213 result += "TD."+p+"cpCurrentDate { color:white; background-color: #C0C0C0; border-width:1px; border:solid thin #800000; }\n";
1214 result += "TD."+p+"cpCurrentDateDisabled { border-width:1px; border:solid thin #FFAAAA; }\n";
1215 result += "TD."+p+"cpTodayText, TD."+p+"cpTodayTextDisabled { border:solid thin #C0C0C0; border-width:1px 0px 0px 0px;}\n";
1216 result += "A."+p+"cpTodayText, SPAN."+p+"cpTodayTextDisabled { height:20px; }\n";
1217 result += "A."+p+"cpTodayText { color:black; }\n";
1218 result += "."+p+"cpTodayTextDisabled { color:#D0D0D0; }\n";
1219 result += "."+p+"cpBorder { border:solid thin #808080; }\n";
1220 result += "</STYLE>\n";
1221 return result;
1222 }
1223
1224 // Return a string containing all the calendar code to be displayed
1225 function CP_getCalendar() {
1226 var now = new Date();
1227 // Reference to window
1228 if (this.type == "WINDOW") { var windowref = "window.opener."; }
1229 else { var windowref = ""; }
1230 var result = "";
1231 // If POPUP, write entire HTML document
1232 if (this.type == "WINDOW") {
1233 result += "<HTML><HEAD><TITLE>Calendar</TITLE>"+this.getStyles()+"</HEAD><BODY MARGINWIDTH=0 MARGINHEIGHT=0 TOPMARGIN=0 RIGHTMARGIN=0 LEFTMARGIN=0>\n";
1234 result += '<CENTER><TABLE WIDTH=100% BORDER=0 BORDERWIDTH=0 CELLSPACING=0 CELLPADDING=0>\n';
1235 }
1236 else {
1237 result += '<TABLE CLASS="'+this.cssPrefix+'cpBorder" WIDTH=144 BORDER=1 BORDERWIDTH=1 CELLSPACING=0 CELLPADDING=1>\n';
1238 result += '<TR><TD ALIGN=CENTER>\n';
1239 result += '<CENTER>\n';
1240 }
1241 // Code for DATE display (default)
1242 // -------------------------------
1243 if (this.displayType=="date" || this.displayType=="week-end") {
1244 if (this.currentDate==null) { this.currentDate = now; }
1245 if (arguments.length > 0) { var month = arguments[0]; }
1246 else { var month = this.currentDate.getMonth()+1; }
1247 if (arguments.length > 1 && arguments[1]>0 && arguments[1]-0==arguments[1]) { var year = arguments[1]; }
1248 else { var year = this.currentDate.getFullYear(); }
1249 var daysinmonth= new Array(0,31,28,31,30,31,30,31,31,30,31,30,31);
1250 if ( ( (year%4 == 0)&&(year%100 != 0) ) || (year%400 == 0) ) {
1251 daysinmonth[2] = 29;
1252 }
1253 var current_month = new Date(year,month-1,1);
1254 var display_year = year;
1255 var display_month = month;
1256 var display_date = 1;
1257 var weekday= current_month.getDay();
1258 var offset = 0;
1259
1260 offset = (weekday >= this.weekStartDay) ? weekday-this.weekStartDay : 7-this.weekStartDay+weekday ;
1261 if (offset > 0) {
1262 display_month--;
1263 if (display_month < 1) { display_month = 12; display_year--; }
1264 display_date = daysinmonth[display_month]-offset+1;
1265 }
1266 var next_month = month+1;
1267 var next_month_year = year;
1268 if (next_month > 12) { next_month=1; next_month_year++; }
1269 var last_month = month-1;
1270 var last_month_year = year;
1271 if (last_month < 1) { last_month=12; last_month_year--; }
1272 var date_class;
1273 if (this.type!="WINDOW") {
1274 result += "<TABLE WIDTH=144 BORDER=0 BORDERWIDTH=0 CELLSPACING=0 CELLPADDING=0>";
1275 }
1276 result += '<TR>\n';
1277 var refresh = windowref+'CP_refreshCalendar';
1278 var refreshLink = 'javascript:' + refresh;
1279 if (this.isShowNavigationDropdowns) {
1280 result += '<TD CLASS="'+this.cssPrefix+'cpMonthNavigation" WIDTH="78" COLSPAN="3"><select CLASS="'+this.cssPrefix+'cpMonthNavigation" name="cpMonth" onmouseup="CP_stop(event)" onChange="'+refresh+'('+this.index+',this.options[this.selectedIndex].value-0,'+(year-0)+');">';
1281 for( var monthCounter=1; monthCounter<=12; monthCounter++ ) {
1282 var selected = (monthCounter==month) ? 'SELECTED' : '';
1283 result += '<option value="'+monthCounter+'" '+selected+'>'+this.monthNames[monthCounter-1]+'</option>';
1284 }
1285 result += '</select></TD>';
1286 result += '<TD CLASS="'+this.cssPrefix+'cpMonthNavigation" WIDTH="10">&nbsp;</TD>';
1287
1288 result += '<TD CLASS="'+this.cssPrefix+'cpYearNavigation" WIDTH="56" COLSPAN="3"><select CLASS="'+this.cssPrefix+'cpYearNavigation" name="cpYear" onmouseup="CP_stop(event)" onChange="'+refresh+'('+this.index+','+month+',this.options[this.selectedIndex].value-0);">';
1289 for( var yearCounter=year-this.yearSelectStartOffset; yearCounter<=year+this.yearSelectStartOffset; yearCounter++ ) {
1290 var selected = (yearCounter==year) ? 'SELECTED' : '';
1291 result += '<option value="'+yearCounter+'" '+selected+'>'+yearCounter+'</option>';
1292 }
1293 result += '</select></TD>';
1294 }
1295 else {
1296 if (this.isShowYearNavigation) {
1297 result += '<TD CLASS="'+this.cssPrefix+'cpMonthNavigation" WIDTH="10"><A CLASS="'+this.cssPrefix+'cpMonthNavigation" HREF="'+refreshLink+'('+this.index+','+last_month+','+last_month_year+');">&lt;</A></TD>';
1298 result += '<TD CLASS="'+this.cssPrefix+'cpMonthNavigation" WIDTH="58"><SPAN CLASS="'+this.cssPrefix+'cpMonthNavigation">'+this.monthNames[month-1]+'</SPAN></TD>';
1299 result += '<TD CLASS="'+this.cssPrefix+'cpMonthNavigation" WIDTH="10"><A CLASS="'+this.cssPrefix+'cpMonthNavigation" HREF="'+refreshLink+'('+this.index+','+next_month+','+next_month_year+');">&gt;</A></TD>';
1300 result += '<TD CLASS="'+this.cssPrefix+'cpMonthNavigation" WIDTH="10">&nbsp;</TD>';
1301
1302 result += '<TD CLASS="'+this.cssPrefix+'cpYearNavigation" WIDTH="10"><A CLASS="'+this.cssPrefix+'cpYearNavigation" HREF="'+refreshLink+'('+this.index+','+month+','+(year-1)+');">&lt;</A></TD>';
1303 if (this.isShowYearNavigationInput) {
1304 result += '<TD CLASS="'+this.cssPrefix+'cpYearNavigation" WIDTH="36"><INPUT NAME="cpYear" CLASS="'+this.cssPrefix+'cpYearNavigation" SIZE="4" MAXLENGTH="4" VALUE="'+year+'" onBlur="'+refresh+'('+this.index+','+month+',this.value-0);"></TD>';
1305 }
1306 else {
1307 result += '<TD CLASS="'+this.cssPrefix+'cpYearNavigation" WIDTH="36"><SPAN CLASS="'+this.cssPrefix+'cpYearNavigation">'+year+'</SPAN></TD>';
1308 }
1309 result += '<TD CLASS="'+this.cssPrefix+'cpYearNavigation" WIDTH="10"><A CLASS="'+this.cssPrefix+'cpYearNavigation" HREF="'+refreshLink+'('+this.index+','+month+','+(year+1)+');">&gt;</A></TD>';
1310 }
1311 else {
1312 result += '<TD CLASS="'+this.cssPrefix+'cpMonthNavigation" WIDTH="22"><A CLASS="'+this.cssPrefix+'cpMonthNavigation" HREF="'+refreshLink+'('+this.index+','+last_month+','+last_month_year+');">&lt;&lt;</A></TD>\n';
1313 result += '<TD CLASS="'+this.cssPrefix+'cpMonthNavigation" WIDTH="100"><SPAN CLASS="'+this.cssPrefix+'cpMonthNavigation">'+this.monthNames[month-1]+' '+year+'</SPAN></TD>\n';
1314 result += '<TD CLASS="'+this.cssPrefix+'cpMonthNavigation" WIDTH="22"><A CLASS="'+this.cssPrefix+'cpMonthNavigation" HREF="'+refreshLink+'('+this.index+','+next_month+','+next_month_year+');">&gt;&gt;</A></TD>\n';
1315 }
1316 }
1317 result += '</TR></TABLE>\n';
1318 result += '<TABLE WIDTH=120 BORDER=0 CELLSPACING=0 CELLPADDING=1 ALIGN=CENTER>\n';
1319 result += '<TR>\n';
1320 for (var j=0; j<7; j++) {
1321
1322 result += '<TD CLASS="'+this.cssPrefix+'cpDayColumnHeader" WIDTH="14%"><SPAN CLASS="'+this.cssPrefix+'cpDayColumnHeader">'+this.dayHeaders[(this.weekStartDay+j)%7]+'</TD>\n';
1323 }
1324 result += '</TR>\n';
1325 for (var row=1; row<=6; row++) {
1326 result += '<TR>\n';
1327 for (var col=1; col<=7; col++) {
1328 var disabled=false;
1329 if (this.disabledDatesExpression!="") {
1330 var ds=""+display_year+LZ(display_month)+LZ(display_date);
1331 eval("disabled=("+this.disabledDatesExpression+")");
1332 }
1333 var dateClass = "";
1334 if ((display_month == this.currentDate.getMonth()+1) && (display_date==this.currentDate.getDate()) && (display_year==this.currentDate.getFullYear())) {
1335 dateClass = "cpCurrentDate";
1336 }
1337 else if (display_month == month) {
1338 dateClass = "cpCurrentMonthDate";
1339 }
1340 else {
1341 dateClass = "cpOtherMonthDate";
1342 }
1343 if (disabled || this.disabledWeekDays[col-1]) {
1344 result += ' <TD CLASS="'+this.cssPrefix+dateClass+'"><SPAN CLASS="'+this.cssPrefix+dateClass+'Disabled">'+display_date+'</SPAN></TD>\n';
1345 }
1346 else {
1347 var selected_date = display_date;
1348 var selected_month = display_month;
1349 var selected_year = display_year;
1350 if (this.displayType=="week-end") {
1351 var d = new Date(selected_year,selected_month-1,selected_date,0,0,0,0);
1352 d.setDate(d.getDate() + (7-col));
1353 selected_year = d.getYear();
1354 if (selected_year < 1000) { selected_year += 1900; }
1355 selected_month = d.getMonth()+1;
1356 selected_date = d.getDate();
1357 }
1358 result += ' <TD CLASS="'+this.cssPrefix+dateClass+'"><A HREF="javascript:'+windowref+this.returnFunction+'('+selected_year+','+selected_month+','+selected_date+');'+windowref+'CP_hideCalendar(\''+this.index+'\');" CLASS="'+this.cssPrefix+dateClass+'">'+display_date+'</A></TD>\n';
1359 }
1360 display_date++;
1361 if (display_date > daysinmonth[display_month]) {
1362 display_date=1;
1363 display_month++;
1364 }
1365 if (display_month > 12) {
1366 display_month=1;
1367 display_year++;
1368 }
1369 }
1370 result += '</TR>';
1371 }
1372 var current_weekday = now.getDay() - this.weekStartDay;
1373 if (current_weekday < 0) {
1374 current_weekday += 7;
1375 }
1376 result += '<TR>\n';
1377 result += ' <TD COLSPAN=7 ALIGN=CENTER CLASS="'+this.cssPrefix+'cpTodayText">\n';
1378 if (this.disabledDatesExpression!="") {
1379 var ds=""+now.getFullYear()+LZ(now.getMonth()+1)+LZ(now.getDate());
1380 eval("disabled=("+this.disabledDatesExpression+")");
1381 }
1382 if (disabled || this.disabledWeekDays[current_weekday+1]) {
1383 result += ' <SPAN CLASS="'+this.cssPrefix+'cpTodayTextDisabled">'+this.todayText+'</SPAN>\n';
1384 }
1385 else {
1386 result += ' <A CLASS="'+this.cssPrefix+'cpTodayText" HREF="javascript:'+windowref+this.returnFunction+'(\''+now.getFullYear()+'\',\''+(now.getMonth()+1)+'\',\''+now.getDate()+'\');'+windowref+'CP_hideCalendar(\''+this.index+'\');">'+this.todayText+'</A>\n';
1387 }
1388 result += ' <BR>\n';
1389 result += ' </TD></TR></TABLE></CENTER></TD></TR></TABLE>\n';
1390 }
1391
1392 // Code common for MONTH, QUARTER, YEAR
1393 // ------------------------------------
1394 if (this.displayType=="month" || this.displayType=="quarter" || this.displayType=="year") {
1395 if (arguments.length > 0) { var year = arguments[0]; }
1396 else {
1397 if (this.displayType=="year") { var year = now.getFullYear()-this.yearSelectStartOffset; }
1398 else { var year = now.getFullYear(); }
1399 }
1400 if (this.displayType!="year" && this.isShowYearNavigation) {
1401 result += "<TABLE WIDTH=144 BORDER=0 BORDERWIDTH=0 CELLSPACING=0 CELLPADDING=0>";
1402 result += '<TR>\n';
1403 result += ' <TD CLASS="'+this.cssPrefix+'cpYearNavigation" WIDTH="22"><A CLASS="'+this.cssPrefix+'cpYearNavigation" HREF="javascript:'+windowref+'CP_refreshCalendar('+this.index+','+(year-1)+');">&lt;&lt;</A></TD>\n';
1404 result += ' <TD CLASS="'+this.cssPrefix+'cpYearNavigation" WIDTH="100">'+year+'</TD>\n';
1405 result += ' <TD CLASS="'+this.cssPrefix+'cpYearNavigation" WIDTH="22"><A CLASS="'+this.cssPrefix+'cpYearNavigation" HREF="javascript:'+windowref+'CP_refreshCalendar('+this.index+','+(year+1)+');">&gt;&gt;</A></TD>\n';
1406 result += '</TR></TABLE>\n';
1407 }
1408 }
1409
1410 // Code for MONTH display
1411 // ----------------------
1412 if (this.displayType=="month") {
1413 // If POPUP, write entire HTML document
1414 result += '<TABLE WIDTH=120 BORDER=0 CELLSPACING=1 CELLPADDING=0 ALIGN=CENTER>\n';
1415 for (var i=0; i<4; i++) {
1416 result += '<TR>';
1417 for (var j=0; j<3; j++) {
1418 var monthindex = ((i*3)+j);
1419 result += '<TD WIDTH=33% ALIGN=CENTER><A CLASS="'+this.cssPrefix+'cpText" HREF="javascript:'+windowref+this.returnMonthFunction+'('+year+','+(monthindex+1)+');'+windowref+'CP_hideCalendar(\''+this.index+'\');" CLASS="'+date_class+'">'+this.monthAbbreviations[monthindex]+'</A></TD>';
1420 }
1421 result += '</TR>';
1422 }
1423 result += '</TABLE></CENTER></TD></TR></TABLE>\n';
1424 }
1425
1426 // Code for QUARTER display
1427 // ------------------------
1428 if (this.displayType=="quarter") {
1429 result += '<BR><TABLE WIDTH=120 BORDER=1 CELLSPACING=0 CELLPADDING=0 ALIGN=CENTER>\n';
1430 for (var i=0; i<2; i++) {
1431 result += '<TR>';
1432 for (var j=0; j<2; j++) {
1433 var quarter = ((i*2)+j+1);
1434 result += '<TD WIDTH=50% ALIGN=CENTER><BR><A CLASS="'+this.cssPrefix+'cpText" HREF="javascript:'+windowref+this.returnQuarterFunction+'('+year+','+quarter+');'+windowref+'CP_hideCalendar(\''+this.index+'\');" CLASS="'+date_class+'">Q'+quarter+'</A><BR><BR></TD>';
1435 }
1436 result += '</TR>';
1437 }
1438 result += '</TABLE></CENTER></TD></TR></TABLE>\n';
1439 }
1440
1441 // Code for YEAR display
1442 // ---------------------
1443 if (this.displayType=="year") {
1444 var yearColumnSize = 4;
1445 result += "<TABLE WIDTH=144 BORDER=0 BORDERWIDTH=0 CELLSPACING=0 CELLPADDING=0>";
1446 result += '<TR>\n';
1447 result += ' <TD CLASS="'+this.cssPrefix+'cpYearNavigation" WIDTH="50%"><A CLASS="'+this.cssPrefix+'cpYearNavigation" HREF="javascript:'+windowref+'CP_refreshCalendar('+this.index+','+(year-(yearColumnSize*2))+');">&lt;&lt;</A></TD>\n';
1448 result += ' <TD CLASS="'+this.cssPrefix+'cpYearNavigation" WIDTH="50%"><A CLASS="'+this.cssPrefix+'cpYearNavigation" HREF="javascript:'+windowref+'CP_refreshCalendar('+this.index+','+(year+(yearColumnSize*2))+');">&gt;&gt;</A></TD>\n';
1449 result += '</TR></TABLE>\n';
1450 result += '<TABLE WIDTH=120 BORDER=0 CELLSPACING=1 CELLPADDING=0 ALIGN=CENTER>\n';
1451 for (var i=0; i<yearColumnSize; i++) {
1452 for (var j=0; j<2; j++) {
1453 var currentyear = year+(j*yearColumnSize)+i;
1454 result += '<TD WIDTH=50% ALIGN=CENTER><A CLASS="'+this.cssPrefix+'cpText" HREF="javascript:'+windowref+this.returnYearFunction+'('+currentyear+');'+windowref+'CP_hideCalendar(\''+this.index+'\');" CLASS="'+date_class+'">'+currentyear+'</A></TD>';
1455 }
1456 result += '</TR>';
1457 }
1458 result += '</TABLE></CENTER></TD></TR></TABLE>\n';
1459 }
1460 // Common
1461 if (this.type == "WINDOW") {
1462 result += "</BODY></HTML>\n";
1463 }
1464 return result;
1465 }
@@ -0,0 +1,122
1 <?php
2
3 require_once('include/admin.inc.php');
4
5 auth_redirect(); // Require logged in user to access this page.
6
7 #Actual logic. Only trigger if something submitted.
8 if('post_twitter' == $_REQUEST['action'])
9 {
10 check_nonce('new-character-twitter');
11
12 #Fetch the password from the DB.
13 $acct = $mtdb->getRow(sprintf("SELECT username, password FROM twitter_user WHERE id = '%d'", $_REQUEST['twitter-account']));
14
15 $post_at = strtotime($_REQUEST['date18']);
16
17 if($post_at)
18 {
19 if($post_at <= strtotime('now'))
20 {
21 #If we can post immediately, do so. Bypass the scheduler whenever possible.
22 #Treat a date/time in the past as immediate.
23 $ret = twitterpost($_REQUEST['message'], $acct->username, $acct->password);
24
25 if($ret)
26 {
27 $info.='Update posted to Twitter. <a href="http://www.twitter.com/'.$acct->username.'">View Twitter</a>.';
28 adminlog('New manual post to Twitter for user '. $acct->username .'.', MTS_TWITTER, MTA_ADD);
29 }
30 else
31 {
32 $error.='There was an error posting to Twitter.';
33 }
34 }
35 else
36 {
37 #No luck, gotta schedule.
38 $mtdb->query(
39 sprintf("INSERT INTO twitter_post (status, user, time, text)VALUES ('scheduled', '%d', FROM_UNIXTIME('%d'), '%s')",
40 mysql_real_escape_string($_REQUEST['twitter-account']),
41 $post_at,
42 mysql_real_escape_string($_REQUEST['message'])
43 )
44 );
45 $info .= "Your tweet for user " . htmlentities($acct->username) . " has been scheduled.";
46 adminlog('Tweet for account ' . $acct->username . ' has been scheduled.', MTS_TWITTER, MTA_ADD);
47 }
48 }
49 else
50 {
51 $error .= 'Could not make sense of your designated time/date. Please try again.';
52 }
53 }
54
55 $characters = $mtdb->getAll("SELECT id, username FROM twitter_user ORDER BY username");
56
57 $scheduled = $mtdb->getAll("SELECT username, text, status, twitter_post.id AS id, time
58 FROM twitter_post JOIN twitter_user
59 ON twitter_post.user = twitter_user.id
60 WHERE twitter_post.status = 'scheduled' ORDER BY time");
61
62 adminhead('Manage Character Twitters');
63 adminmenu();
64 ?>
65
66 <h2>Manage Character Twitters</h2>
67 <form method="post" action="character-twitter.php">
68 <?php nonce_field('new-character-twitter'); ?>
69 <input type="hidden" name="action" value="post_twitter" />
70 <p><select name="twitter-account">
71 <option value="">Select twitter</option>
72 <?php foreach($characters as $c) {
73 printf( '<option value="%s">%s</option>', htmlentities($c->id), htmlentities($c->username) );
74 } ?>
75 </select></p>
76 <p style="padding-bottom:1em;">
77 <input type="text" name="message" maxlength="140" size="70" />
78 At: <script type="text/javascript" src="CalendarPopup.js" ></script>
79 <script type="text/javascript">
80 var cal18 = new CalendarPopup("testdiv1");
81 cal18.setCssPrefix("TEST");
82 </script>
83 <INPUT TYPE="text" NAME="date18" VALUE="now" SIZE=25>
84 <A HREF="#" onClick="cal18.select(document.forms[0].date18,'anchor18','yyyy/MM/dd'); return false;" TITLE="cal18.select(document.forms[0].date18,'anchor18','MM/dd/yyyy'); return false;" NAME="anchor18" ID="anchor18">select</A>
85 <DIV ID="testdiv1" STYLE="position:absolute;visibility:hidden;background-color:white;layer-background-color:white;"></DIV>
86 <input type="submit" value="Send" />
87 </p>
88 </form>
89
90 <table class="widefat">
91 <thead>
92 <tr>
93 <th scope="col">User</th>
94 <th scope="col">Tweet</th>
95 <th scope="col">Time</th>
96 <th scope="col"></th>
97 </tr>
98 </thead>
99
100 <tbody id="the-list">
101 <?php
102 $alternate=false;
103 foreach( $scheduled as $s ) {
104 $alternate=!$alternate;
105 ?>
106 <tr <?php if($alternate) echo 'class="alternate"'; ?>>
107 <td><?php echo $s->username; ?></td>
108 <td><?php echo $s->text; ?></td>
109 <td><?php echo htmlentities($s->time); ?></td>
110 <td style="text-align: center;"><a class="delete" href="delete-tweet.php?tweet_id=<?php echo $s->id; ?>">Delete</a></td>
111 </tr>
112 <?php
113 }
114 ?>
115 </tbody>
116 </table>
117
118 <script type="text/javascript" src="<?php echo SITE_HOST.SITE_PATH; ?>/resources.js"></script>
119
120 <?php
121 adminfooter();
122 ?> No newline at end of file
@@ -0,0 +1,19
1 <?php
2
3 require_once('include/admin.inc.php');
4
5 auth_redirect(); // Require logged in user to access this page.
6
7 // Deliberatly don't pass a nonce here, always AYS
8 check_nonce('delete-strip-'.(int)$_REQUEST['strip_id']);
9
10 if(!deletestrip( $_REQUEST['strip_id'] ))
11 {
12 adminlog("Error deleting strip $_REQUEST[strip_id]:".mysql_error(), MTS_STRIP, MTA_DELETE, E_ERROR);
13 mtdie('Error deleting the specified strip.','SQL Error');
14 }
15
16 adminlog("Strip $_REQUEST[strip_id] deleted.", MTS_STRIP, MTA_DELETE);
17 _redirect( ADMIN_PATH . '/manage-comics.php?deleted=success' );
18
19 ?> No newline at end of file
@@ -0,0 +1,19
1 <?php
2
3 require_once('include/admin.inc.php');
4
5 auth_redirect(); // Require logged in user to access this page.
6
7 // Deliberatly don't pass a nonce here, always AYS
8 check_nonce('delete-page-'.$_REQUEST['page_name']);
9
10 if(!deletepage( $_REQUEST['page_name'] ))
11 {
12 adminlog("Error deleting page $_REQUEST[page_name]: ".mysql_error(), MTS_PAGE, MTA_DELETE, E_ERROR);
13 mtdie('Error deleting the specified page.','SQL Error');
14 }
15
16 adminlog("Page $_REQUEST[page_name] deleted.", MTS_PAGE, MTA_DELETE);
17 _redirect( ADMIN_PATH . '/manage-pages.php?deleted=success' );
18
19 ?>
@@ -0,0 +1,17
1 <?php
2
3 require_once('include/admin.inc.php');
4
5 auth_redirect(); // Require logged in user to access this page.
6
7 // Deliberatly don't pass a nonce here, always AYS
8 check_nonce('delete-rant-'.(int)$_REQUEST['rant_id']);
9
10 if(!deleterant( $_REQUEST['rant_id'] ))
11 {
12 adminlog("Error deleting rant $_REQUEST[rant_id]: ".mysql_error(), MTS_RANT, MTA_DELETE, E_ERROR);
13 mtdie('Error deleting the specified rant.','SQL Error');
14 }
15
16 _redirect( ADMIN_PATH . '/manage-rants.php?deleted=success' );
17 ?> No newline at end of file
@@ -0,0 +1,26
1 <?php
2
3 require_once('include/admin.inc.php');
4
5 auth_redirect(); // Require logged in user to access this page.
6
7 // Deliberatly don't pass a nonce here, always AYS
8 check_nonce('delete-tweet-'.(int)$_REQUEST['tweet_id']);
9
10 //Filter input first
11 $victim = (int)$_REQUEST['tweet_id'];
12
13 if($victim)
14 {
15 $r = $mtdb->query("DELETE FROM twitter_post WHERE id = '$victim'");
16 if(!$r)
17 {
18 adminlog('Error deleting scheduled tweet ' . $victim, MTS_TWITTER, MTA_DELETE, E_ERROR);
19 mtdie('Error deleting the specified tweet.', 'SQL Error');
20 }
21 }
22
23 adminlog("Tweet $victim deleted.", MTS_TWITTER, MTA_DELETE);
24 _redirect( ADMIN_PATH . '/character-twitter.php?deleted=success' );
25
26 ?> No newline at end of file
@@ -0,0 +1,26
1 <?php
2
3 require_once('include/admin.inc.php');
4
5 auth_redirect(); // Require logged in user to access this page.
6
7 // Deliberatly don't pass a nonce here, always AYS
8 check_nonce('delete-twitteruser-'.(int)$_REQUEST['id']);
9
10 //Filter input first
11 $victim = (int)$_REQUEST['id'];
12
13 if($victim)
14 {
15 $r = $mtdb->query("DELETE FROM twitter_user WHERE id = '$victim'");
16 if(!$r)
17 {
18 adminlog('Error deleting specified twitter user ' . $victim, MTS_TWITTER, MTA_DELETE, E_ERROR);
19 mtdie('Error deleting the specified twitter user.', 'SQL Error');
20 }
21 }
22
23 adminlog("Twitter $victim deleted.", MTS_TWITTER, MTA_DELETE);
24 _redirect( ADMIN_PATH . '/manage-twitter-users.php?deleted=success' );
25
26 ?> No newline at end of file
@@ -0,0 +1,258
1 <?php
2
3 require_once('include/admin.inc.php');
4
5 auth_redirect(); // Require logged in user to access this page.
6
7 $strip = new Strip();
8 $strip->id = (int)$_REQUEST['strip_id'];
9 $strip = getstrip($strip->id);
10
11 if( $_POST ) {
12
13 // Form Elements
14 $strip->new_id = (int)$_POST['strip_new_id'] ? (int)$_POST['strip_new_id'] : $strip->id;
15 $strip->published = empty($_POST['strip_date']) ? time() : strtotime( $_POST['strip_date'] );
16 $strip->type = (int)$_POST['strip_type'];
17 $strip->title = trim($_POST['strip_title']);
18 $strip->transcript_posted = $_POST['content'];
19 $strip->book = trim($_POST['book']);
20 $strip->page = trim($_POST['page']);
21
22 if( '' == $strip->title ) mtdie('Strips must be supplied with titles.');
23
24 $YESTERDAY = mktime(0,0,0, date('m'), date('d')-1, date('Y'));
25
26 switch($_POST['action']) {
27 case 'new_comic':
28
29 check_nonce('new-strip');
30
31 // Ensure that dates are not in the past
32 if( $strip->published < $YESTERDAY )
33 mtdie('Strips may not be backdated. Enter a date today or in the future.');
34
35 if( !is_valid_upload('comicFile') )
36 {
37 adminlog("Image upload failed.", MTS_STRIP, MTA_ADD, E_WARNING);
38 mtdie('If you want to upload a new comic, you must provide said comic.','Strip upload failed.');
39 }
40
41 // get image type and target extension
42 $imagedata = getimagesize($_FILES['comicFile']['tmp_name']);
43 $strip->media = $imagedata[2];
44 $fileext = $mtdb->getOne( 'SELECT extension FROM media_t WHERE id = ' . (int)$strip->media );
45
46 if(strlen($fileext) < 3)
47 {
48 //bad image upload type
49 adminlog("Bad image type upload on new strip. Invalid media type.", MTS_STRIP, MTA_ADD, E_ERROR);
50 mtdie('Bad image type upload on new strip. Invalid media type.');
51 }
52
53 // Insert new strip into the database, get a real $strip->id
54 if(!insertstrip( $strip ))
55 {
56 adminlog("Error on insertion of new strip: ".mysql_error(), MTS_STRIP, MTA_ADD, E_ERROR);
57 mtdie('Error on insertion of new strip: '.mysql_error(), 'SQL Error');
58 }
59
60 // Store the uploaded file to xxxx-0.ext
61 $basefile = $strip->published <= time() ?
62 sprintf(SITE_PATH_ABS.'/'.SITE_STRIP.'/'.'%04d.%s', $strip->id, $fileext) :
63 sprintf(SITE_PATH_ABS.'/'.SITE_STRIP.'/restricted/'.'%04d.%s', $strip->id, $fileext);
64 if(!move_uploaded_file($_FILES['comicFile']['tmp_name'], $basefile))
65 {
66 adminlog("Filesystem error in storing image.", MTS_STRIP, MTA_ADD, E_ERROR);
67 mtdie('There was a problem storing the uploaded strip image. Please <s>harass</s> contact support.','Filesystem Error');
68 }
69
70 // Alert Twitter if the strip is for immediate publication
71 if( $strip->published <= time() )
72 twitterpost("Comic ".$strip->id." posted: ".SITE_HOST.SITE_PATH."/strip/".$strip->id);
73
74 $info.="<p>Comic posted!</p>";
75 break;
76
77 case 'edit_comic':
78 if( 0 >= $strip->new_id ) mtdie('Strip numbers must be numeric, greater than 0.');
79 if( 0 >= $strip->id ) mtdie('Existing strip number, in the form, was zero. This should never happen.');
80
81 // When updating, $strip->id is the old strip number. Update in place first. Possibly adjust strip number later.
82 check_nonce('save-strip-'.$strip->id);
83
84 // If uploading, get filetype. If not uploading, filetype got loaded from database earlier.
85 if( is_valid_upload('comicFile') ) {
86 $imagedata = getimagesize($_FILES['comicFile']['tmp_name']);
87 $strip->media = $imagedata[2];
88 }
89 $fileext = $mtdb->getOne( 'SELECT extension FROM media_t WHERE id=' . (int)$strip->media );
90
91 if(strlen($fileext) < 3)
92 {
93 //bad image upload type
94 adminlog("Bad image type upload on strip ".$strip->id.". Invalid media type.", MTS_STRIP, MTA_UPDATE, E_ERROR);
95 mtdie('Bad image type upload on strip '.$strip->id.'. Invalid media type.');
96 }
97
98 // Update existing strip
99 if(!updatestrip( $strip ) )
100 {
101 adminlog("Failed to update strip ".$strip->id.".", MTS_STRIP, MTA_UPDATE);
102 mtdie('Error updating strip: ' . mysql_error(), 'SQL Error');
103 }
104
105 if( is_valid_upload('comicFile') ) { // If uploading, store the uploaded file to xxxx-n.ext
106 $basefile = $strip->published <= time() ?
107 sprintf(SITE_PATH_ABS.'/'.SITE_STRIP.'/'.'%04d.%s', $strip->id, $fileext) :
108 sprintf(SITE_PATH_ABS.'/'.SITE_STRIP.'/restricted/'.'%04d.%s', $strip->id, $fileext);
109
110 if(!move_uploaded_file($_FILES['comicFile']['tmp_name'], $basefile))
111 {
112 adminlog("Filesystem error in saving image.", MTS_STRIP, MTA_UPDATE, E_ERROR);
113 mtdie("There was a problem storing the uploaded strip image. Please <s>harass</s> contact support.", 'Filesystem Error');
114 }
115 adminlog("Image replaced for comic ".$strip->id.".", MTS_STRIP, MTA_UPDATE);
116 }
117 // No new file uploaded. Do nuffink.
118
119 // Conditionally broadcast success
120 if( $_POST['broadcast'] ) {
121 #Limit broadcast message to 60 characters. Compose it now.
122 $b_msg = 'Comic ' . $strip->id . ' updated: ' . substr(trim($_REQUEST['broadcast_message']), 0, 60) . ', ' . SITE_HOST . SITE_PATH . "/strip/" . $strip->id;
123
124 rsspost($b_msg, SITE_HOST.SITE_PATH.'/strip/'.$strip->id);
125 twitterpost($b_msg);
126 $info.="<p>Update broadcasted with message '$b_msg'.</p>";
127 }
128
129 $info.="<p>Changes saved. <a href=\"".SITE_HOST.SITE_PATH."/index.php?strip_id=".$strip->id."\">View on site</a>.";
130 break;
131
132 default:
133 adminlog("User did something strange.", MTS_STRIP, MTA_MODIFY);
134 mtdie('You know, it would be <em>really</em> nice if you avoided nonsensical actions.');
135 }
136
137 $info = savetranscript($strip) . $info;
138
139 # If the strip number changed, swap strips sequentially to shuffle it into place
140 if( $strip->id != $strip->new_id ) {
141 $f = fopen(SITE_PATH_ABS.'/'.SITE_STRIP.'/'.SITE_STRIP_LOCK, 'w');
142 flock($f, LOCK_EX);
143
144 while( $strip->new_id < $strip->id ) { // Move this strip backward
145 swap_strips( $strip->id - 1, $strip->id );
146 $strip->id--;
147 }
148 while( $strip->id < $strip->new_id ) { // Move this strip forward
149 swap_strips( $strip->id + 1, $strip->id );
150 $strip->id++;
151 }
152 $strip->id = $strip->new_id;
153 close($f);
154 }
155 }
156
157 ////////////////////// Display Edit Form ////////////////////////
158 $strip = getstrip($strip->id);
159 gettranscript($strip);
160
161 adminhead('Edit Comic');
162 adminmenu('manage-comics.php');
163
164 ?>
165
166 <h2>Edit Comic</h2>
167
168 <form action="edit-comic.php" method="post" enctype="multipart/form-data" name="post" id="post">
169 <?php nonce_field('save-strip-'.$strip->id); ?>
170 <input type="hidden" name="action" value="edit_comic" />
171 <input type="hidden" name="strip_id" size="40" tabindex="1" value="<?php echo $strip->id; ?>" />
172 <div id="poststuff">
173
174 <div id="moremeta">
175 <div id="grabit" class="dbx-group">
176
177 <fieldset id="slugdiv" class="dbx-box">
178 <h3 class="dbx-handle">Comic Type</h3>
179 <div class="dbx-content"><select name="strip_type">
180 <?php
181 $types = $mtdb->getAll( 'SELECT id, description FROM strip_t ORDER BY id' );
182 foreach( $types as $k=>$v )
183 printf('<option value="%s" %s>%s</option>', htmlentities($v->id), ($strip->type == $v->id ? 'selected="selected"' : '' ), htmlentities($v->description));
184
185 ?>
186 </select></div>
187 </fieldset>
188
189 <fieldset id="pubdatediv" class="dbx-box">
190 <h3 class="dbx-handle">Post Date</h3>
191 <div class="dbx-content"> <input type="text" name="strip_date" value="<?php echo htmlentities( date( 'Y-m-d H:i:s', $strip->published )); ?>" /> </div>
192 </fieldset>
193
194 <fieldset id="pubdatediv" class="dbx-box">
195 <h3 class="dbx-handle">Strip Number</h3>
196 <div class="dbx-content"> <input type="text" name="strip_new_id" size="6" value="<?php echo $strip->id; ?>" id="strip_id" /> </div>
197 </fieldset>
198
199 <fieldset id="stripdiv" class="dbx-box">
200 <h3 class="dbx-handle">Replace Comic</h3>
201 <div class="dbx-content"> <input type="hidden" name="MAX_FILE_SIZE" value="10000000" /><input name="comicFile" type="file" tabindex="2" size="12"/> </div>
202 </fieldset>
203
204 <fieldset id="broadcastdiv" class="dbx-box">
205 <h3 class="dbx-handle">Broadcast Update</h3>
206 <div class="dbx-content">
207 <label><input type="radio" name="broadcast" value="0" checked="checked" />No</label>
208 <label><input type="radio" name="broadcast" value="1" />Yes</label>
209 <input type="text" name="broadcast_message" maxlength="60" size="15" />
210 </div>
211 </fieldset>
212
213 <?php
214 $file = get_stripimage_filename( $strip );
215 if( file_exists( SITE_PATH_ABS.'/'.$file ) ){
216 ?>
217 <fieldset id="pubdatediv" class="dbx-box">
218 <h3 class="dbx-handle">Strip</h3>
219 <div class="dbx-content"> <a target="_new" href="<?php echo SITE_HOST.SITE_PATH; ?>/index.php?strip_id=<?php echo $strip->id;
220 ?>"><img src="<?php echo SITE_HOST.SITE_PATH.'/'.$file; ?>" width="170" /></a> </div>
221 </fieldset>
222 <?php
223 }
224 ?>
225
226 <fieldset id="bookpagenumberdiv" class="dbx-box">
227 <h3 class="dbx-handle">Book Page Number</h3>
228 <div class="dbx-content"> <input type="text" name="book" size="3" value="<?php echo $strip->book; ?>" />-<input type="text" name="page" size="4" value="<?php echo $strip->page; ?>" /></div>
229 </fieldset>
230 </div>
231 </div>
232
233 <fieldset id="titlediv">
234 <legend>Title</legend>
235 <div><input type="text" name="strip_title" size="40" tabindex="1" value="<?php echo numeric_entities(utfentities($strip->title)) ?>" id="title" /></div>
236 </fieldset>
237
238 <fieldset id="postdivrich">
239 <legend>Transcript</legend>
240 <style type="text/css">
241 #postdivrich table, #postdivrich #quicktags {border-top: none;}
242 #quicktags {border-bottom: none; padding-bottom: 2px; margin-bottom: -1px;}
243 #edButtons {border-bottom: 1px solid #ccc;}
244 </style>
245 <div><textarea class="mceEditor" rows="27" cols="40" name="content" tabindex="3" id="content"><?php echo htmlentities($strip->transcript, ENT_COMPAT, 'UTF-8'); ?></textarea></div>
246 </fieldset>
247
248 <p class="submit">
249 <input name="edit_comic" type="submit" id="edit_comic" tabindex="4" accesskey="s" value="Save Changes" />
250 </p>
251
252 </div>
253 </form>
254
255 <?php
256 adminfooter();
257 ?>
258
@@ -0,0 +1,37
1 <?php
2
3 require_once('include/admin.inc.php');
4
5 auth_redirect(); // Require logged in user to access this page.
6
7 $type = $mtdb->getRow( 'SELECT id, name FROM meta_t WHERE id=' . (int)$_GET['edit'] )
8 or mtdie("Invalid metatype number!");
9
10 adminhead('Metatypes');
11 adminmenu('manage-metatypes.php');
12
13 ?>
14
15 <h2>Edit Metatype Information</h2>
16
17 <form action="manage-metatypes.php" method="post" name="post" id="post">
18 <?php nonce_field('save-metatype-'.$type->id); ?>
19 <input type="hidden" name="action" value="edit_meta" />
20 <input type="hidden" name="type_id" value="<?php echo $type->id; ?>" />
21
22 <div id="poststuff">
23
24 <table class="editform" width="100%" cellspacing="2" cellpadding="5">
25 <tr>
26 <th scope="row" width="33%">Name</th>
27 <td width="66%"><input name="name" type="text" id="name" value="<?php echo htmlentities($type->name); ?>" /></td>
28 </tr>
29 </table>
30
31 <p class="submit"><input type="submit" value="Save &raquo;" name="submit" /></p>
32
33 </div>
34
35 </form>
36
37 <?php adminfooter(); ?>
@@ -0,0 +1,158
1 <?php
2 require_once('include/admin.inc.php');
3
4 auth_redirect(); // Require logged in user to access this page.
5
6 $page = new Page();
7 $page->url_name = $_REQUEST['page_name'];
8 $page = getpage($page->url_name);
9
10 if( $_POST ) {
11 $page->url_name = $_POST['page_name'] ? $_POST['page_name'] : preg_replace('/\s+/', '_', strtolower(trim($_POST['title'])));
12 $page->status = $_POST['page_status'] == 'published' ? 'published' : 'draft';
13 $page->title = $_POST['title'];
14 $page->body = $_POST['content'];
15 $page->style = $_POST['style'];
16
17 if( USING_TIDY ) {
18 $tidy = new tidy;
19 $config = $tidy->getConfig();
20 $tidy->parseString( $page->body, $config, 'UTF8' );
21 $tidy->cleanRepair();
22 $page->body = tidy_get_output($tidy);
23 }
24
25 $action = isset($_POST['publish']) ? 'post' : 'edit';
26
27 if( isset( $_POST['publish'] ) ) $page->status = 'published'; // If [publish] button is used, ignore radio button
28
29
30 switch( $_POST['action'] ) {
31 case 'new_page':
32 check_nonce('new-page');
33 if( !insertpage($page) )
34 {
35 adminlog("Error inserting page.", MTS_PAGE, MTA_INSERT, E_ERROR);
36 mtdie('There was an error inserting the page into the database.', 'SQL Error');
37 }
38 break;
39
40 case 'savepage':
41 check_nonce('save-page-' . $page->url_name);
42 updatepage($page);
43 break;
44 }
45 if( $upload_info ) $info.=$upload_info;
46 if( $upload_error ) $error.=$upload_error;
47 if( $error ) $action='edit';
48
49 if( 'post' == $action ) _redirect( ADMIN_PATH . '/manage-pages.php?saved=success' );
50
51 $info.= '<p>' . ( $page->status === 'draft' ? 'Page draft saved.' : sprintf('Page published. <a href="%s%s/static.php?name=%s">View on site</a>.', SITE_HOST, SITE_PATH, $page->url_name) ) . '</p>';
52
53 } elseif( !$page->url_name ) {
54 mtdie('Attempted to edit page with no name supplied.', 'Bad Request');
55 }
56
57 /////////////////////// Display Edit Form ///////////////////////
58
59
60 adminhead('Edit Page');
61 adminmenu('manage-pages.php');
62
63
64 ?>
65
66 <script language="javascript" type="text/javascript" src="include/tiny_mce/tiny_mce.js"></script>
67 <script language="javascript" type="text/javascript">
68 tinyMCE.init({
69 mode : "exact",
70 elements: "content",
71 theme : "advanced",
72 theme_advanced_buttons1 : "bold,italic,underline,separator,strikethrough,justifyleft,justifycenter,justifyright,justifyfull,bullist,numlist,undo,redo,link,unlink,code,formatselect",
73 theme_advanced_buttons2 : "",
74 theme_advanced_buttons3 : "",
75 theme_advanced_toolbar_location : "top",
76 theme_advanced_toolbar_align : "left",
77 theme_advanced_path_location : "bottom",
78 extended_valid_elements : "a[name|href|target|title|onclick],img[class|src|border=0|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name],hr[class|width|size|noshade],font[face|size|color|style],span[class|align|style]",
79 theme_advanced_blockformats : "p,h3,h4,h5,h6"
80 });
81 </script>
82
83
84 <h2>Editing Page "<?php echo htmlentities($page->title, ENT_COMPAT, 'UTF-8') ; ?>"</h2>
85
86 <form enctype="multipart/form-data" action="edit-page.php" method="post" name="post" id="post">
87 <?php nonce_field('save-page-'.$page->url_name); ?>
88 <input type="hidden" name="action" value="savepage" />
89
90 <div id="poststuff">
91
92 <div id="moremeta">
93 <div id="grabit" class="dbx-group">
94
95 <fieldset id="pagenamediv" class="dbx-box">
96 <h3 class="dbx-handle">Page URL Name</h3>
97 <div class="dbx_content">
98 <input type="text" name="page_name" value="<?php echo $page->url_name ?>" />
99 </div>
100 </fieldset>
101
102 <fieldset id="statusdiv" class="dbx-box">
103 <h3 class="dbx-handle">Published Status</h3>
104 <div class="dbx-content">
105 <label><input type="radio" name="page_status" value="draft" <?php echo $page->status == 'draft' ? 'checked="checked"' : ''; ?>/>Draft</label>
106 <label><input type="radio" name="page_status" value="published" <?php echo $page->status == 'published' ? 'checked="checked"' : ''; ?>/>Published</label>
107 </div>
108 </fieldset>
109
110
111 </div>
112 </div>
113
114 <fieldset id="titlediv">
115 <legend>Title</legend>
116 <div><input type="text" name="title" size="40" tabindex="1" value="<?php echo htmlentities($page->title, ENT_COMPAT, 'UTF-8'); ?>" id="title" /></div>
117 </fieldset>
118
119 <fieldset id="postdivrich">
120 <legend>Page</legend>
121 <style type="text/css">
122 #postdivrich table, #postdivrich #quicktags {border-top: none;}
123 #quicktags {border-bottom: none; padding-bottom: 2px; margin-bottom: -1px;}
124 #edButtons {border-bottom: 1px solid #ccc;}
125 </style>
126 <div><textarea class="mceEditor" rows="13" cols="40" name="content" tabindex="3" id="content"><?php echo htmlentities($page->body, ENT_COMPAT, 'UTF-8'); ?></textarea></div>
127 </fieldset>
128
129
130
131 <p class="submit">
132 <input name="save" type="submit" id="save" tabindex="3" value="Save and Continue Editing" style="font-weight: bold;" />
133 <input name="publish" type="submit" id="publish" tabindex="5" accesskey="p" value="Publish" />
134 </p>
135
136
137
138 <div class="dbx-b-ox-wrapper">
139
140 <fieldset id="cssdivrich">
141 <legend>Optional CSS</legend>
142
143 <style type="text/css">
144 #postdivrich table, #postdivrich #quicktags {border-top: none;}
145 #quicktags {border-bottom: none; padding-bottom: 2px; margin-bottom: -1px;}
146 #edButtons {border-bottom: 1px solid #ccc;}
147 </style>
148 <div><textarea rows="13" cols="40" name="style" tabindex="6" id="style"><?php echo htmlentities($page->style, ENT_COMPAT, 'UTF-8'); ?></textarea></div>
149
150 </fieldset>
151
152 </div>
153
154
155 </div>
156 </form>
157
158 <?php adminfooter() ?>
@@ -0,0 +1,346
1 <?php
2 require_once('include/admin.inc.php');
3
4 auth_redirect(); // Require logged in user to access this page.
5
6 $rant = new Rant();
7 $rant->id = (int)$_REQUEST['rant_id'];
8 $rant = getrant($rant->id);
9
10 if( $_POST ) {
11 $rant->published = strtotime( $_POST['rant_date'] );
12 $rant->status = $_POST['rant_status'] == 'published' ? 'published' : 'draft';
13 $rant->side = $_POST['rant_side'] == 'left' ? 'left' : 'right';
14 $rant->author = (int)$_POST['rant_author'];
15 $rant->title = $_POST['title'];
16 $rant->body = preg_replace('/&nbsp;/', '', $_POST['content']);
17 $rant->link = $_POST['link'];
18 $rant->imagetext = $_POST['rant_imagetext'];
19
20 if( USING_TIDY ) {
21 $tidy = new tidy;
22 $config = $tidy->getConfig();
23 $tidy->parseString( $rant->body, $config, 'UTF8' );
24 $tidy->cleanRepair();
25 $rant->body = tidy_get_output($tidy);
26 }
27
28 $action = isset($_POST['publish']) ? 'post' : 'edit';
29
30 if( isset( $_POST['publish'] ) ) $rant->status = 'published'; // If [publish] button is used, ignore radio button
31
32
33 $source_rantimage_filename = $_FILES['ranterImage']['tmp_name'];
34 extract( pre_upload_rant_image( $source_rantimage_filename ) );
35 if( $upload_error ) $error.=$upload_error;
36
37 $source_rantattachment_filename = Array();
38 for($i = 0; $i < count($_FILES['rant_attachment']['error']); $i++) {
39 if( !is_valid_upload('rant_attachment', $i) ) {
40 $error .= "<p>Attachment $i was not uploaded properly</p>";
41 $source_rantattachment_filename[] = '';
42 } else {
43 $source_rantattachment_filename[] = $_FILES['rant_attachment']['tmp_name'][$i];
44 }
45 }
46
47 switch( $_POST['action'] ) {
48 case 'new_rant':
49
50 check_nonce('new-rant');
51
52 if( ! $doing_upload ) {
53 // Use default rant image for this contributor.
54 $contributor = get_userdatabyid( $rant->author );
55 $image_data = getimagesize(SITE_PATH_ABS .'/'. SITE_RANT .'/'. $contributor->default_image);
56 $rant->imagetype = $image_data[2] ? $image_data[2] : 'NULL';
57 $source_rantimage_filename = $contributor->default_image;
58 } else {
59 $rant->imagetype = $upload_imagetype;
60 }
61
62 $rant->id = insertrant($rant);
63 if( $rant->id === false )
64 {
65 adminlog("Error on rant insertion: ".mysql_error(), MTS_RANT, MTA_INSERT, E_ERROR);
66 mtdie('There was an error inserting the rant into the database.', 'SQL Error');
67 }
68
69 for($i = 0; $i < count($source_rantattachment_filename); $i++) {
70 if('' == $source_rantattachment_filename[$i]) continue;
71
72 $upload_error = $upload_info = '';
73 extract( save_upload_rant_attachment($_FILES['rant_attachment']['tmp_name'][$i], $rant->id) );
74
75 if( $upload_error ) $error.=$upload_error;
76 if( $upload_info ) {
77 $info .= $upload_info;
78 $rant->body = preg_replace('/(href|src)=\"([^\"]*?)\\{'.($i+1).'\\}(.*?)\"/', '\1="'.get_rantattachment_filename($rant_attachment_id).'"', $rant->body);
79 }
80 }
81
82 if(count($_FILES['rant_attachment']['error']) > 0)
83 updaterant($rant);
84
85 if( $doing_upload ) {
86 extract( save_upload_rant_image( $source_rantimage_filename, $rant ) );
87 if( $upload_info ) $info.=$upload_info;
88 if( $upload_error ) $error.=$upload_error;
89 } elseif($rant->imagetype != 'NULL') {
90 extract( save_stock_rant_image( $source_rantimage_filename, $rant ) );
91 if( $upload_info ) $info.=$upload_info;
92 if( $upload_error ) $error.=$upload_error;
93 }
94
95 break;
96
97 case 'saverant':
98
99 check_nonce('save-rant-' . $rant->id);
100
101 if( isset( $_POST['rant_reverttodefaultimage'] ) ) {
102 // Use default rant image for this contributor, copy it into place
103 $contributor = get_userdatabyid( $rant->author );
104 $imagedata = getimagesize(SITE_PATH_ABS .'/'. SITE_RANT .'/'. $contributor->default_image);
105 $rant->imagetype = $imagedata[2] ? $imagedata[2] : 'NULL';
106 if($rant->imagetype != 'NULL')
107 extract( save_stock_rant_image( $contributor->default_image, $rant ) );
108 adminlog("Reverting to user's default rant image for rant ".$rant->id.".", MTS_RANT, MTA_UPDATE);
109
110 } elseif( $doing_upload ) {
111 $rant->imagetype = $upload_imagetype;
112 extract( save_upload_rant_image( $source_rantimage_filename, $rant ) );
113 adminlog("Uploading new rant image for rant ".$rant->id.".", MTS_RANT, MTA_UPDATE);
114 if( $upload_info ) $info.=$upload_info;
115 if( $upload_error ) $error.=$upload_error;
116 }
117
118 foreach($_POST['delete_attachment'] as $attachment)
119 deleteattachment($attachment);
120
121 $existing_attachments = $mtdb->getAll('SELECT ra.id AS id, extension FROM rant_attachment ra JOIN media_t ON ra.media = media_t.id WHERE ra.rant = '.$rant->id.' ORDER BY id');
122 for($i = 0; $i < count($existing_attachments); $i++) {
123 $rant->body = preg_replace('/(href|src)=\"([^\"]*?)\\{'.($i+1).'\\}(.*?)\"/', '\1="'.get_rantattachment_filename($existing_attachments[$i]->id).'"', $rant->body);
124 }
125
126 for($j = $i; $j < count($source_rantattachment_filename) + $i; $j++) {
127 if('' == $source_rantattachment_filename[$j - $i]) continue;
128
129 $upload_error = $upload_info = '';
130 extract( save_upload_rant_attachment($_FILES['rant_attachment']['tmp_name'][$j - $i], $rant->id) );
131
132 if( $upload_error ) $error.=$upload_error;
133 if( $upload_info ) {
134 $info .= $upload_info;
135 $rant->body = preg_replace('/(href|src)=\"([^\"]*?)\\{'.($i+1).'\\}(.*?)\"/', '\1="'.get_rantattachment_filename($rant_attachment_id).'"', $rant->body);
136 }
137 }
138
139 updaterant($rant);
140
141 if($rant->status != 'draft' && $_POST['broadcast'] &&
142 ($rant->published <= mktime(0,0,0, date('m'), date('d')-1, date('Y'))))
143 {
144 rsspost('Rant '.$rant->id.' updated.', SITE_HOST.SITE_PATH.'/rant/'.$rant->id);
145 twitterpost('Rant '.$rant->id.' updated: '.SITE_HOST.SITE_PATH.'/rant/'.$rant->id);
146 }
147
148 break;
149 }
150 if( $error ) $action='edit';
151
152 if( 'post' == $action ) _redirect( ADMIN_PATH . '/manage-rants.php?saved=success' );
153
154 $info.= '<p>' . ( $rant->status === 'draft' ? 'Rant draft saved.' : sprintf('Rant published. <a href="%s%s/index.php?rant_id=%d">View on site</a>.', SITE_HOST, SITE_PATH, $rant->id) ) . '</p>';
155
156 } elseif( !$rant->id ) {
157 mtdie('Attempted to edit rant with no rantid supplied.', 'Bad Request');
158 }
159
160 /////////////////////// Display Edit Form ///////////////////////
161
162
163 adminhead('Edit Rant');
164 adminmenu('manage-rants.php');
165
166 ?>
167
168 <script language="javascript" type="text/javascript" src="include/tiny_mce/tiny_mce.js"></script>
169 <script language="javascript" type="text/javascript">
170 tinyMCE.init({
171 mode : "textareas",
172 theme : "advanced",
173 theme_advanced_buttons1 : "save,newdocument,|,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,formatselect,fontsizeselect,|,cut,copy,paste,pastetext,|,bullist,numlist,|,outdent,indent,blockquote,|,undo,redo,|,link,unlink,anchor,image,|,cleanup,code,|,insertdate,inserttime,preview,|,forecolor,backcolor",
174 theme_advanced_buttons2 : "hr,removeformat,visualaid,|,sub,sup,|,charmap,emotions,iespell,media,advhr,|,fullscreen,|,visualchars,nonbreaking,template,blockquote,pagebreak,|,insertfile,insertimage",
175 theme_advanced_buttons3 : "",
176 plugin_preview_width : "350",
177 plugin_preview_height : "700",
178 language:"en",
179 theme_advanced_toolbar_location:"top",
180 theme_advanced_toolbar_align:"left",
181 theme_advanced_statusbar_location:"bottom",
182 theme_advanced_resizing:"1",
183 theme_advanced_resize_horizontal:"",
184 paste_convert_middot_lists:"1",
185 paste_remove_spans:"1",
186 paste_remove_styles:"1",
187 gecko_spellcheck:"1",
188 extended_valid_elements : "a[name|href|target|title|onclick],img[class|src|border=0|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name],hr[class|width|size|noshade],font[face|size|color|style],span[class|align|style],iframe[src|width|height|scrolling|frameborder|style]",
189 theme_advanced_blockformats : "p,h3,h4,h5,h6",
190 plugins:"safari,inlinepopups,autosave,paste,media,fullscreen,contextmenu,advimage,advlink,visualchars,preview"
191 });
192 </script>
193
194 <h2>Editing Rant "<?php echo htmlentities($rant->title, ENT_COMPAT, 'UTF-8') ; ?>"</h2>
195
196 <form enctype="multipart/form-data" action="edit-rant.php" method="post" name="post" id="post">
197 <?php nonce_field('save-rant-'.$rant->id); ?>
198 <input type="hidden" name="action" value="saverant" />
199 <input type="hidden" name="rant_id" value="<?php echo $rant->id; ?>" />
200
201 <div id="poststuff">
202
203 <div id="moremeta">
204 <div id="grabit" class="dbx-group">
205
206 <fieldset id="slugdiv" class="dbx-box">
207 <h3 class="dbx-handle">Side</h3>
208 <div class="dbx-content"><select name="rant_side">
209 <?php
210 $sides = array('left'=>'Left','right'=>'Right');
211 foreach( $sides as $k=>$v ) {
212 printf('<option value="%s" %s>%s</option>', htmlentities($k, ENT_COMPAT, 'UTF-8'), ($rant->side == $k ? 'selected="selected"' : '' ), htmlentities($v) );
213 }
214 ?>
215 </select></div>
216 </fieldset>
217
218 <fieldset id="authordiv" class="dbx-box">
219 <h3 class="dbx-handle">Author</h3>
220 <div class="dbx-content"><select name="rant_author"><?php
221 $contrib = $mtdb->getAll('select id,name from contributor');
222 foreach( $contrib as $k=>$v ) {
223 printf('<option value="%s" %s>%s</option>', htmlentities($v->id, ENT_COMPAT, 'UTF-8'), ( $v->id == $rant->author ? 'selected="selected"' : '' ), htmlentities($v->name) );
224 } ?>
225 </select></div>
226 </fieldset>
227
228 <fieldset id="pubdatediv" class="dbx-box">
229 <h3 class="dbx-handle">Post Date</h3>
230 <div class="dbx-content"> <input type="text" name="rant_date" value="<?php echo htmlentities( date( 'Y-m-d H:i:s', $rant->published )); ?>" /> </div>
231 </fieldset>
232
233 <fieldset id="statusdiv" class="dbx-box">
234 <h3 class="dbx-handle">Published Status</h3>
235 <div class="dbx-content">
236 <label><input type="radio" name="rant_status" value="draft" <?php echo $rant->status == 'draft' ? 'checked="checked"' : ''; ?>/>Draft</label>
237 <label><input type="radio" name="rant_status" value="published" <?php echo $rant->status == 'published' ? 'checked="checked"' : ''; ?>/>Published</label>
238 </div>
239 </fieldset>
240
241 <?php if($rant->status != 'draft') { ?>
242 <fieldset id="broadcastdiv" class="dbx-box">
243 <h3 class="dbx-handle">Broadcast Update</h3>
244 <div class="dbx-content">
245 <label><input type="radio" name="broadcast" value="0" checked="checked" />No</label>
246 <label><input type="radio" name="broadcast" value="1" />Yes</label>
247 </div>
248 </fieldset>
249 <?php } ?>
250
251 </div>
252 </div>
253
254 <fieldset id="titlediv">
255 <legend>Title</legend>
256 <div><input type="text" name="title" size="40" tabindex="1" value="<?php echo htmlentities($rant->title, ENT_COMPAT, 'UTF-8'); ?>" id="title" /></div>
257 </fieldset>
258
259 <fieldset id="linkdiv">
260 <legend>Link</legend>
261 <div><input type="text" name="link" size="40" tabindex="2" value="<?php echo htmlentities($rant->link, ENT_COMPAT, 'UTF-8'); ?>" id="link" /></div>
262 </fieldset>
263
264 <fieldset id="postdivrich">
265 <legend>Post</legend>
266 <style type="text/css">
267 #postdivrich table, #postdivrich #quicktags {border-top: none;}
268 #quicktags {border-bottom: none; padding-bottom: 2px; margin-bottom: -1px;}
269 #edButtons {border-bottom: 1px solid #ccc;}
270 </style>
271 <div><textarea class="mceEditor" rows="13" cols="40" name="content" tabindex="3" id="content"><?php echo htmlentities($rant->body, ENT_COMPAT, 'UTF-8'); ?></textarea></div>
272 </fieldset>
273
274
275
276 <p class="submit">
277 <input name="save" type="submit" id="save" tabindex="3" value="Save and Continue Editing" style="font-weight: bold;" />
278 <input name="publish" type="submit" id="publish" tabindex="5" accesskey="p" value="Publish" />
279 </p>
280
281
282
283 <div class="dbx-b-ox-wrapper">
284
285 <fieldset id="rant-image" class="dbx-box">
286 <h3 class="dbx-handle">Image</h3>
287 <div>
288 <table border="0">
289 <tr><td valign="top">
290 <?php
291
292 $contributor = get_userdatabyid( $rant->author );
293 $rantimage_filename = get_rantimage_filename($rant);
294 if( ! file_exists( SITE_PATH_ABS.'/' . $rantimage_filename )) {
295 // no image in place yet
296 $rantimage_filename = SITE_RANT.'/' . $contributor->default_image;
297 if( file_exists( SITE_PATH_ABS.'/' . $rantimage_filename )) {
298 echo 'Currently using default rant image for this contributor. <a href="user-edit.php?edit='.$currentuser->id.'">Change default</a>.';
299 } else {
300 $rantimage_filename = false;
301 echo 'There is currently no image associated with this rant, <br/>and no default rant image associated with this contributor.
302 <br/><a href="user-edit.php?edit=' . $currentuser->id . '">Add a default rant image to your profile.</a>';
303 }
304 } else {
305 echo 'Custom rant image is specified.';
306 }
307 ?>
308
309 <p>Upload new rant image:<br/>
310 <input type="hidden" name="MAX_FILE_SIZE" value="10000000" />
311 <input name="ranterImage" type="file"/>
312 </p>
313 <p><input type="checkbox" name="rant_reverttodefaultimage" /> Revert to default rant image.</p>
314 </td><td>
315 <?php if ( false !== $rantimage_filename ): ?>
316 <p><img src="<?php echo SITE_HOST . '/' . SITE_PATH . '/' . $rantimage_filename; ?>" width="150" /></p>
317 <?php endif; ?>
318 </td></tr>
319 <tr><td>
320 <p>Rant image alt text:</p>
321 <input type="text" name="rant_imagetext" size="40" tabindex="2" value="<?php echo $rant->imagetext; ?>" id="rant_imagetext" />
322 </td></tr>
323 <tr id="rant_attachments"><td>
324 <p>Attach files:</p>
325 <ol id="rant_attachment_list">
326 <?php
327 $attachments = $mtdb->getAll('SELECT ra.id AS id, extension FROM rant_attachment ra JOIN media_t ON ra.media = media_t.id WHERE ra.rant = '.$rant->id.' ORDER BY id');
328 foreach($attachments as $k=>$v)
329 printf('<li><input type="checkbox" name="delete_attachment[]" value="%d" /> <a href="%s/%s/%s">%s</a></li>', $v->id, SITE_HOST, SITE_PATH, get_rantattachment_filename($v->id), get_rantattachment_filename($v->id));
330 ?>
331 </ol>
332 <p>(Checked attachments will be deleted on submit.)</p>
333 <script src="include/rants.js" type="text/javascript"></script>
334 <a href="#rant_attachments" onclick="new_rant_attachment()">(add attachment)</a>
335 </td></tr>
336 </table>
337 </div>
338 </fieldset>
339
340 </div>
341
342
343 </div>
344 </form>
345
346 <?php adminfooter() ?>
@@ -0,0 +1,51
1 <?php
2
3 require_once('include/admin.inc.php');
4
5 auth_redirect(); // Require logged in user to access this page.
6
7 $type = get_typeByID( $_GET['edit'] )
8 or mtdie("Invalid type number!");
9
10 $metas = get_allMetaTypes();
11
12 adminhead('Types');
13 adminmenu('manage-types.php');
14
15 ?>
16
17 <h2>Edit Type Information</h2>
18
19 <form action="manage-types.php" method="post" name="post" id="post">
20 <?php nonce_field('save-type-'.$type->id); ?>
21 <input type="hidden" name="action" value="edit_type" />
22 <input type="hidden" name="type_id" value="<?php echo $type->id; ?>" />
23
24 <div id="poststuff">
25
26 <table class="editform" width="100%" cellspacing="2" cellpadding="5">
27 <tr>
28 <th scope="row" width="33%">Name</th>
29 <td width="66%"><input name="name" type="text" id="name" value="<?php echo htmlentities($type->name); ?>" /></td>
30 </tr>
31 <tr>
32 <th scope="row" width="33%">Description</th>
33 <td width="66%"><input name="description" type="text" id="description" value="<?php echo htmlentities($type->description); ?>" /></td>
34 </tr>
35 <th scope="row" width="33%">Metatypes</th>
36 <td width="66%">
37 <?php
38 foreach($metas as $s) {
39 echo '<input id="c-' . $s->id . '" type="checkbox" name="meta[' . $s->id . ']"' . ( _objectInArrayWithIdExists( $s->id, $type->meta ) ? ' checked="checked"' : '') . '/> <label for="c-' . $s->id . '">' . $s->name . '</label><br/>';
40 }
41 ?></td>
42 </tr>
43 </table>
44
45 <p class="submit"><input type="submit" value="Save &raquo;" name="submit" /></p>
46
47 </div>
48
49 </form>
50
51 <?php adminfooter(); ?>
@@ -0,0 +1,58
1 <?php
2 /******************************
3 * This script dependent on *
4 * XML_Feed_Parser PEAR module *
5 ******************************/
6
7 require_once('include/admin.inc.php');
8 require_once("PEAR.php");
9 require_once("XML/Feed/Parser.php");
10
11 // Workaround since DreamHost disables allow_url_fopen
12 $ch = curl_init();
13 $timeout = 5; // set to zero for no timeout
14 curl_setopt ($ch, CURLOPT_URL, FEED_URL);
15 curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
16 curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
17 $feed_src = curl_exec($ch);
18 curl_close($ch);
19
20 // Use if allow_url_fopen not disabled
21 // $feed_src = file_get_contents(FEED_URL);
22
23 $feed = new XML_Feed_Parser($feed_src);
24
25 for ($count = 0; $count < 5; $count++) {
26 $entry = $feed->getEntryByOffset($count);
27 $link = mysql_real_escape_string($entry->link);
28 $title = mysql_real_escape_string($entry->title);
29 $date = $entry->pubdate;
30
31 $mtdb->query("INSERT INTO fredart (pubdate, title, link)
32 VALUES (FROM_UNIXTIME($date), '$title', '$link')", false);
33 }
34
35 header('Content-Type: text/xml');
36 header('Content-Length: 440');
37 ?>
38 <?php echo "<?xml version=\"1.0\" ?>\n"; ?>
39 <methodResponse>
40 <params>
41 <param>
42 <value>
43 <struct>
44 <member>
45 <name>flerror</name>
46 <value>
47 <boolean>0</boolean>
48 </value>
49 </member>
50 <member>
51 <name>message</name>
52 <value>Thanks for the ping.</value>
53 </member>
54 </struct>
55 </value>
56 </param>
57 </params>
58 </methodResponse>
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
@@ -0,0 +1,4
1 <Files *.php>
2 Order Deny,Allow
3 Deny from all
4 </Files> No newline at end of file
@@ -0,0 +1,148
1 <?php
2
3 /* Megatokyo Website Administration */
4
5 require_once('../LocalSettings.php');
6
7 // Core lib
8 require_once('html.php');
9 require_once('mysql.php');
10 require_once('cookies.php');
11 require_once('functions.php');
12 require_once('error.php');
13
14 require_once('uploads.php');
15 require_once('nonce.php');
16
17 // Objects
18 require_once('rants.php');
19 require_once('user.php');
20 require_once('strip.php');
21 require_once('transcript.php');
22 require_once('type.php');
23 require_once('pages.php');
24 require_once('extra.php');
25 require_once('twitter.php');
26 require_once('tumblr.php');
27 require_once('images.php');
28 require_once('rss.php');
29
30 require_once('twitteroauth/twitteroauth.php');
31
32 $mtdb = new MysqlStore();
33 $mtdb->connect( DB_SERVER, DB_WRITE_USER, DB_WRITE_PASS, DB_NAME );
34
35 /* TODO: Move these definitions to LocalSettings.php */
36 if ( !defined('RANTIMG') )
37 define('RANTIMG', '../rantimgs/');
38
39 define('USING_TIDY', false);
40
41
42
43 /* These function are all for core authentication. */
44
45 // Call mysql to hash a password
46 function mt_hash_password($password) {
47 global $mtdb;
48 return $mtdb->getOne('SELECT SHA1("' . mysql_real_escape_string($password) . '")') ;
49 }
50
51 // Remove invalid characters from username. Permit only alpha, underscore, period, at, hypen
52 function sanitize_username( $username ) {
53 return preg_replace('|[^a-z_.@-]|i', '', $username);
54 }
55
56 // Attempt to login with a username and password. If from cookies, set already_hashed = true.
57 function mt_login($username, $password, $already_hashed = false) {
58 global $error,$mtdb;
59
60 if ( '' == $username )
61 return false;
62
63 if ( '' == $password ) {
64 $error = ('<strong>ERROR</strong>: The password field is empty.');
65 return false;
66 }
67
68 $username = sanitize_username( $username );
69
70 $login = $mtdb->getRow( 'SELECT id,name,email,nameplate,default_image,default_link,password FROM contributor WHERE name = "' . mysql_real_escape_string($username) . '"');
71 if (!$login) {
72 $error = ('<strong>ERROR</strong>: Invalid username or password.');
73 adminlog("Failed login attempt from ".$_SERVER['REMOTE_ADDR']." for $username.", MTS_LOGIN, MTA_CHANGE);
74 //logthis ('AUTH: Failed login attempt from ' . $_SERVER["REMOTE_ADDR"], var_export( $_SERVER, true ) );
75 return false;
76 } else {
77 // If the password is already_md5, it has been double hashed.
78 // Otherwise, it is plain text.
79 if ( $already_hashed && $username == $login->name && $login->password == $password) {
80 global $currentuser;
81 $currentuser=$login;
82 return true;
83 }
84
85 if (!$already_hashed) {
86 $passhash = mt_hash_password($password);
87 if( $username == $login->name && $passhash == $login->password ) {
88 global $currentuser;
89 $currentuser=$login;
90 return true;
91 }
92 }
93 $error = ('<strong>ERROR</strong>: Invalid username or password.');
94 adminlog("Failed login attempt from ".$_SERVER['REMOTE_ADDR']." for $username.", MTS_LOGIN, MTA_CHANGE);
95 //logthis ('AUTH: Failed login attempt from ' . $_SERVER["REMOTE_ADDR"], var_export( $_SERVER, true ) );
96 return false;
97 }
98 }
99
100 // Attempt to login using cookies with failback to HTTP Basic Auth. If that fails, return a 401 to the browser.
101 function auth_basic() {
102 if ( !empty($_COOKIE[USER_COOKIE]) && mt_login($_COOKIE[USER_COOKIE], $_COOKIE[PASS_COOKIE], true) )
103 return;
104
105 // Either there is no cookie or the cookie is not valid
106 if (!isset($_SERVER['PHP_AUTH_USER']) || !mt_login($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) ) {
107 header('WWW-Authenticate: Basic realm="My Realm"');
108 header('HTTP/1.0 401 Unauthorized');
109 die('You do not have permission to view this page.');
110 }
111 }
112
113 // Attempt to login using cookies. If that fails, redirect to login.php to get credentials.
114 function auth_redirect($showloginui=true) {
115 // Checks if a user is logged in, if not redirects them to the login page
116 if ( (!empty($_COOKIE[USER_COOKIE]) &&
117 !mt_login($_COOKIE[USER_COOKIE], $_COOKIE[PASS_COOKIE], true)) ||
118 (empty($_COOKIE[USER_COOKIE])) ) {
119 nocache_headers();
120
121 if($showloginui) _redirect( ADMIN_PATH . '/login.php?redirect_to=' . urlencode($_SERVER['REQUEST_URI']));
122 die('You do not have permission to view this page.');
123 }
124 }
125
126 // Safe redirect, defaults to Temporary
127 function _redirect($location, $status = 302) {
128 $location = preg_replace('|[^a-z0-9-~+_.?#=&;,/:%]|i', '', $location);
129 $strip = array('%0d', '%0a');
130 $location = str_replace($strip, '', $location);
131
132 if ( substr(php_sapi_name(), 0, 3) != 'cgi' )
133 header('Status: '.$status); // This causes problems on IIS and some FastCGI setups
134
135 header("Location: $location");
136 die();
137 }
138
139 // When doing redirect to login form, ensure headers are never cached.
140 function nocache_headers() {
141 @ header('Expires: Wed, 11 Jan 1984 05:00:00 GMT');
142 @ header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
143 @ header('Cache-Control: no-cache, must-revalidate, max-age=0');
144 @ header('Pragma: no-cache');
145 }
146
147
148 ?>
@@ -0,0 +1,52
1 <?php
2
3 /* Functions to read, write, compute cookies */
4
5
6 if( !defined('COOKIEHASH') )
7 define('COOKIEHASH', md5('megatokyo') ); // Generate a slightly more obscure cookie name
8 if ( !defined('USER_COOKIE') )
9 define('USER_COOKIE', 'megatokyoadmin_user_'. COOKIEHASH);
10 if ( !defined('PASS_COOKIE') )
11 define('PASS_COOKIE', 'megatokyoadmin_pass_'. COOKIEHASH);
12
13 if ( !defined('COOKIEPATH') )
14 define('COOKIEPATH', ADMIN_PATH . '/' );
15 if ( !defined('COOKIE_DOMAIN') )
16 define('COOKIE_DOMAIN', false);
17
18 // Get the username and password stored in the cookie
19 function mt_get_cookie_login() {
20 if ( empty($_COOKIE[USER_COOKIE]) || empty($_COOKIE[PASS_COOKIE]) )
21 return false;
22
23 return array('login' => $_COOKIE[USER_COOKIE], 'password' => $_COOKIE[PASS_COOKIE]);
24 }
25
26 // Store username and password in a cookie
27 function mt_setcookie($username, $password, $already_md5 = false, $siteurl = '', $remember = false) {
28 global $mtdb;
29 if ( !$already_md5 )
30 $password = mt_hash_password($password);
31
32 if ( empty($siteurl) )
33 $cookiepath = COOKIEPATH;
34 else
35 $cookiepath = preg_replace('|https?://[^/]+|i', '', $siteurl . '/' );
36
37 if ( $remember )
38 $expire = time() + 31536000;
39 else
40 $expire = 0;
41
42 setcookie(USER_COOKIE, $username, $expire, $cookiepath );
43 setcookie(PASS_COOKIE, $password, $expire, $cookiepath );
44 }
45
46 // Force the cookies to expire
47 function mt_clearcookie() {
48 setcookie(USER_COOKIE, ' ', time() - 36000, COOKIEPATH );
49 setcookie(PASS_COOKIE, ' ', time() - 36000, COOKIEPATH );
50 }
51
52 ?> No newline at end of file
@@ -0,0 +1,77
1 <?php
2
3 define('MTS_LOGIN', 1); // User login
4 define('MTS_USER', 2); // Changes to user information
5
6 define('MTS_PAGE', 3); // Modifying static pages
7 define('MTS_RANT', 4); // Modifying rants
8 define('MTS_SCRATCH', 5); // Additions to the scratchpad
9 define('MTS_STRIP', 6); // Modifying strips
10 define('MTS_TWITTER', 9); // Modifications to Twitter presets
11 define('MTS_TYPE', 7); // Changes in the type manager
12 define('MTS_TYPE_META', 8); // Changes in the metatype manager
13 define('MTS_TUMBLR', 10);
14
15
16
17 define('MTA_ADD', 'create'); // Creation action
18 define('MTA_INSERT', 'create'); // Creation action
19 define('MTA_DELETE', 'delete'); // Deletion action
20 define('MTA_REMOVE', 'delete'); // Deletion action
21 define('MTA_MODIFY', 'update'); // Modification action
22 define('MTA_UPDATE', 'update'); // Modification action
23 define('MTA_CHANGE', 'update'); // Modification action
24
25 function adminlog($msg, $section, $action, $level=E_USER_NOTICE, $email=false)
26 {
27 global $mtdb, $currentuser;
28
29 $sql = sprintf('INSERT INTO admin_log (contributor, section, action, level, message) VALUES (%s, %d, "%s", %d, "%s")',
30 (is_numeric($currentuser->id) ? $currentuser->id : "NULL"), $section, mysql_real_escape_string($action), $level, mysql_real_escape_string($msg));
31 $mtdb->query( $sql ) or die($sql."<br>".mysql_error()."<br>\n".var_export(debug_backtrace()));
32
33 // Log all important sorts of messages in the Apache log
34 if( $level & (E_USER_WARNING | E_USER_ERROR) ) {
35 error_log($msg, 0);
36 }
37
38 // Email critical messages and those for which email is requested
39 if($email || E_USER_ERROR == $level || E_ERROR == $level) {
40 // Pretty printing
41 switch($level) {
42 case E_USER_NOTICE:
43 case E_NOTICE:
44 $importance = 'Notice';
45 break;
46 case E_USER_WARNING:
47 case E_WARNING:
48 $importance = 'Warning';
49 break;
50 case E_USER_ERROR:
51 case E_ERROR:
52 $importance = 'Error';
53 break;
54 default:
55 $importance = "Other - $level";
56 break;
57 }
58
59 switch($section) {
60 case MTS_LOGIN: $area = 'User login'; break;
61 case MTS_USER: $area = 'Modify user'; break;
62 case MTS_PAGE: $area = 'Modify page'; break;
63 case MTS_RANT: $area = 'Modify rant'; break;
64 case MTS_SCRATCH: $area = 'Modify scratchpd'; break;
65 case MTS_STRIP: $area = 'Modify strips'; break;
66 case MTS_TYPE: $area = 'Modify strip types'; break;
67 case MTS_TYPE_META: $area = 'Modify strip metatypes'; break;
68 case MTS_TWITTER: $area = 'Modify Twitter'; break;
69 default:
70 $area = 'Undefined Area'; break;
71 }
72
73 error_log("Megatokyo Administrative Notice\r\nPriority level: $importance\r\nReported by: ".$currentuser->name."\r\nSection: $area\r\n$msg", 1, SITE_CONTACT);
74 }
75 }
76
77 ?>
@@ -0,0 +1,82
1 <?php
2
3 /* This library of functions helps the /extra file mananger */
4
5 function extra_delete_file($inode) {
6 $file = extra_file_from_inode($inode);
7 return unlink($file->fullpath);
8 }
9
10 function extra_sort_file_objects($a, $b) {
11 $an = strtolower($a->name);
12 $bn = strtolower($b->name);
13 if( $an == $bn ) return 0;
14 return ( $an < $bn ) ? -1 : 1;
15 }
16
17 function extra_handle_upload() {
18 global $info,$error,$dir;
19
20 if( !$_FILES['extra_file'] ) return false;
21
22 if( '' == $_FILES['extra_file']['name'] ) return false;
23 if( UPLOAD_ERR_NO_FILE == $_FILES['extra_file']['error'] ) return false;
24 if( 0 == $_FILES['extra_file']['size'] ) return false;
25
26 $dest = $_FILES['extra_file']['name'];
27
28 if(isset( $_POST['name'] )) $dest = $_POST['name'];
29 $dest = extra_sanitize_filename($dest);
30
31 if( !is_uploaded_file( $_FILES['extra_file']['tmp_name'] )) return false;
32 if( move_uploaded_file($_FILES['extra_file']['tmp_name'], $dir.'/'.$dest) ) return $true;
33
34 return false;
35 }
36
37 function extra_file_from_inode($inode) {
38 global $dir;
39 $files = extra_get_directory_list($dir);
40 foreach($files as $f) {
41 if( $f->inode == $inode ) return $f;
42 }
43 return false;
44 }
45
46 function extra_sanitize_filename( $raw_filename ) {
47 $filename = str_replace('/', '');
48 if( $filename !== $raw_filename) return false;
49 }
50
51 function extra_get_directory_list($dir) {
52 if( !is_dir( $dir ) ) return false;
53 if( ! $handle = opendir( $dir ) ) return false;
54
55 $files = array();
56
57 class ExtraFile {
58 var $name;
59 var $rwx;
60 var $mtime;
61 var $inode;
62
63 function ExtraFile($path, $file) {
64 $this->name = $file;
65 $this->fullpath = $path . $file;
66 $this->rwx = is_readable($this->fullpath) ? 'r' : '-';
67 $this->rwx.= is_writable($this->fullpath) ? 'w' : '-';
68 $this->rwx.= is_executable($this->fullpath) ? 'x' : '-';
69 $this->mtime = filemtime($this->fullpath);
70 $this->inode = fileinode($this->fullpath);
71 }
72
73 }
74
75 while (false !== ($file = readdir($handle))) {
76 if( is_file( $dir.'/'.$file )) $files[] = new ExtraFile($dir.'/', $file);
77 }
78
79 return $files;
80 }
81
82 ?> No newline at end of file
@@ -0,0 +1,91
1 <?php
2
3 /* Generic string processors */
4
5 if(!function_exists('http_build_query')) {
6 function http_build_query( $formdata, $numeric_prefix = null, $key = null ) {
7 $res = array();
8 foreach ((array)$formdata as $k=>$v) {
9 $tmp_key = urlencode(is_int($k) ? $numeric_prefix.$k : $k);
10 if ($key) $tmp_key = $key.'['.$tmp_key.']';
11 $res[] = ( ( is_array($v) || is_object($v) ) ? http_build_query($v, null, $tmp_key) : $tmp_key."=".urlencode($v) );
12 }
13 $separator = ini_get('arg_separator.output');
14 return implode($separator, $res);
15 }
16 }
17
18 function wp_get_referer() {
19 if ( !empty( $_SERVER['HTTP_REFERER'] ) ) return $_SERVER['HTTP_REFERER'];
20 return false;
21 }
22
23 function clean_url( $url, $protocols = null ) {
24 if ('' == $url) return $url;
25 $url = preg_replace('|[^a-z0-9-~+_.?#=!&;,/:%]|i', '', $url);
26 $strip = array('%0d', '%0a');
27 $url = str_replace($strip, '', $url);
28 if ( strpos($url, '://') === false && substr( $url, 0, 1 ) != '/' && !preg_match('/^[a-z0-9-]+?\.php/i', $url) )
29 $url = 'http://' . $url;
30
31 $url = preg_replace('/&([^#])(?![a-z]{2,8};)/', '&#038;$1', $url);
32 return $url;
33 }
34
35 // Like htmlspecialchars except don't double-encode HTML entities
36 function mt_specialchars( $text, $quotes = false ) {
37
38 $text = str_replace('&&', '&#038;&', $text);
39 $text = str_replace('&&', '&#038;&', $text);
40 $text = preg_replace('/&(?:$|([^#])(?![a-z1-4]{1,8};))/', '&#038;$1', $text);
41 $text = str_replace('<', '&lt;', $text);
42 $text = str_replace('>', '&gt;', $text);
43 /* if ( 'double' === $quotes ) {
44 $text = str_replace('"', '&quot;', $text);
45 } elseif ( 'single' === $quotes ) {
46 $text = str_replace("'", '&#039;', $text);
47 } else
48 */
49 if ( $quotes ) {
50 $text = str_replace('"', '&quot;', $text);
51 $text = str_replace("'", '&#039;', $text);
52 }
53 return $text;
54 }
55
56 function add_query_arg($param,$value,$url) {
57 return $url . ( (strpos( $url, '?' )===false) ? '?' : '&' ) . $param . '=' . urlencode($value);
58 }
59
60 function Excerpt( $excerpt, $maxlen = 455) {
61 $excerpt = strip_tags( $excerpt );
62 if (strlen($excerpt) > $maxlen) {
63 $excerpt = substr($excerpt,0,$maxlen-3) . '...';
64 }
65 return $excerpt;
66 }
67
68 /* Type names may consist of digits, letters, -, ', :, and whitespace */
69 function sanitize_type_name( $name ) {
70 return preg_replace( '/[^\d\w\':\s-]+/', '', $name );
71 }
72
73 function check_type_name( $name ) {
74 global $error;
75
76 if( $name == '' )
77 $error.='A type must be supplied with a name, but none was given. Valid characters include letters, numbers, apostrophes, colons, and whitespace.';
78 elseif ( $name !== sanitize_type_name($name) )
79 $error.='Supplied name contains invalid characters. Valid characters include letters, numbers, apostrophes, colons, and whitespace.';
80 else
81 return true;
82 return false;
83 }
84
85 function _objectInArrayWithIdExists( $id, $arrobj ) {
86 foreach( $arrobj as $v )
87 if( $v->id == $id ) return true;
88 return false;
89 }
90
91 ?> No newline at end of file
@@ -0,0 +1,247
1 <?php
2
3 // Capture error and info messages in these variables, rendered in adminmenu() as a box below the menu bar.
4 $error='';
5 $info='';
6
7 // write from doctype, html, head, body
8 function adminhead($title = '') {
9 ?>
10 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
11 <html xmlns="http://www.w3.org/1999/xhtml" lang="en-US" xml:lang="en-US">
12 <head>
13 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
14 <title>Megatokyo Administrative Dashboard<?php if( $title ) echo " &#8212; $title"; ?></title>
15 <link rel="stylesheet" href="<?php echo ADMIN_PATH; ?>/wp-admin.css" type="text/css" />
16 <link type="application/rss+xml" rel="alternate" title="Admin Log" href="<?php printf('%s%s/%s/adminlog.xml', SITE_HOST, SITE_PATH, SITE_ADMIN) ?>" />
17 <link type="application/rss+xml" rel="alternate" title="Scratchpad" href="<?php printf('%s%s/%s/scratchpad.xml', SITE_HOST, SITE_PATH, SITE_ADMIN) ?>" />
18 </head>
19 <body>
20 <?php
21 }
22
23 // structure of the top level menubar
24 //'manage-statusbox.php' => 'Update Statusbox',
25 $menus = array(
26 'index.php' => 'Dashboard',
27 'post-comic.php?next=yes' => 'Post Next Comic',
28 'post-comic.php' => 'Post Comic',
29 'post-rant.php' => 'Write Rant',
30 'post-twitter.php' => 'Update Feeds',
31 'post-page.php' => 'Add page',
32 'manage-comics.php' => 'Manage',
33 'users.php' => 'Users'
34 );
35
36 // structure of the second level menubar
37 $submenu['manage-comics.php'] = array(
38 'manage-comics.php' => 'Comics',
39 'manage-rants.php' => 'Rants' ,
40 'manage-pages.php' => 'Pages',
41 'manage-types.php' => 'Types',
42 'manage-twitter-users.php' => 'Manage Twitter Users',
43 'manage-metatypes.php' => 'Metatypes',
44 'swap-comics.php' => 'Swap Comics',
45 'character-twitter.php' => 'Character Twitters',
46 'view-adminlog.php' => 'View Admin Log'
47 );
48
49 function adminmenu($current='') {
50 global $menus, $submenu, $error, $info;
51
52 if( $current ) {
53 $curS = $curT = $current;
54 } else {
55 $curS = $curT = basename( $_SERVER["PHP_SELF"] );
56 }
57
58
59 foreach( $submenu as $l=>$L ) {
60 foreach( $L as $k=>$v ) {
61 if( $k == $curS ) {
62 $curT = $l;
63 }
64 }
65 }
66 $current_sub_menu = false;
67
68 ?>
69 <div id="wphead">
70 <h1>Megatokyo Site Administration <span>(<a href="<?php echo SITE_HOST . SITE_PATH; ?>">View site &raquo;</a>)</span></h1>
71 </div>
72 <div id="user_info"><p>Howdy, <strong><?php getCurrentUser(); ?></strong>. [<a href="<?php echo ADMIN_PATH;
73 ?>/login.php?action=logout" title="Log out of this account">Sign Out</a>] </p></div>
74
75
76 <ul id="adminmenu">
77 <?php
78 foreach ( $menus as $url=>$desc ) {
79 printf ( " <li><a href=\"%s/%s\"%s>%s</a></li>\n", ADMIN_PATH, $url, ( $curT == $url ? ' class="current"' : '' ), htmlentities($desc) );
80 if( $curT == $url && isset($submenu[$url]) ) {
81 $current_sub_menu = $submenu[$url];
82 }
83 }
84 ?></ul><?php
85
86 if( $current_sub_menu ) {
87 ?><ul id="submenu"><?php
88 foreach( $current_sub_menu as $url => $desc ) {
89 printf ( " <li><a href=\"%s/%s\"%s>%s</a></li>\n", ADMIN_PATH, $url, ( $curS == $url ? ' class="current"' : '' ), htmlentities($desc) );
90 }
91 ?></ul><?php
92 } else {
93 ?><div id="minisub"></div><?php
94 }
95 ?>
96
97 <div class="clear"></div>
98
99 <?php
100 if( $_GET['deleted'] && $_GET['deleted'] == 'success' ) $info.='<p>Deleted successfully.</p>';
101 if( $_GET['saved'] && $_GET['saved'] == 'success' ) $info.='<p>Changes saved successfully.</p>';
102
103 if( $error ) echo "<div class=\"error fade\">$error</div>";
104 if( $info ) echo "<div class=\"updated fade\">$info</div>";
105 ?>
106 <div class="wrap">
107 <?php
108 }
109
110 function adminfooter($copy = true) {
111 ?>
112 </div>
113 <?php if( $copy ) { ?>
114 <div id="footer">
115 <p class="logo">Style based on <a href="http://wordpress.org/">Wordpress</a>. Powered by Taiyaki.</p>
116 </div>
117 <?php } ?>
118 </body>
119 </html>
120 <?php
121 }
122
123 function pagination( $page, $total ) {
124 ?><p class="pagenav"><?php
125 if( 1 < $page ) {
126 ?><a class="prev" href="?page=<?php echo $page-1; ?>">&laquo; Previous Page</a> <?php
127 }
128 for( $page_num = 1; $page_num <= $total; $page_num++ ) {
129 if ( $page == $page_num ) {
130 echo "<span>$page_num</span>";
131 } else {
132 if ( $page_num < 4 || ( $page_num >= $page - 3 && $page_num <= $page + 3 ) || $page_num > $total - 3 ) {
133 ?><a class="page-numbers" href="?page=<?php echo $page_num; ?>"><?php echo $page_num; ?></a><?php
134 $in=true;
135 } elseif( $in==true ) {
136 echo ' ... ';
137 $in=false;
138 }
139 }
140 }
141 if( $page < $total ) {
142 ?> <a class="next" href="?page=<?php echo $page+1; ?>">Next Page &raquo;</a><?php
143 }
144 ?></p><?php
145 }
146
147 set_error_handler('handle_error');
148
149 function handle_error($errno, $errstr, $errfile, $errline, $errcontext) {
150 switch ($errno) {
151 case E_USER_WARNING:
152 case E_USER_NOTICE:
153 case E_WARNING:
154 case E_NOTICE:
155 case E_CORE_WARNING:
156 case E_COMPILE_WARNING:
157 break;
158 case E_USER_ERROR:
159 case E_ERROR:
160 case E_PARSE:
161 case E_CORE_ERROR:
162 case E_COMPILE_ERROR:
163
164 header('Content-Type: text/html; charset=utf-8');
165
166 if (eregi('^(sql)$', $errstr)) {
167 $errstr = "SQL Error " . mysql_errno() . ': ' . mysql_error();
168 }
169
170 $message = "Error#$errno: $errstr";
171 //logthis( $message, "in $errfile at line $errline" );
172 mtdie( $message, 'Critical Site Error' );
173 }
174 }
175
176 function logthis($str,$extra='') {
177 error_log( $str, 0 );
178 if( $extra ) error_log( "Megatokyo Site Error\r\n$str\r\n$extra", 1, SITE_CONTACT );
179 }
180
181 function mtdie($message,$title='') {
182 header('Content-Type: text/html; charset=utf-8');
183
184 ?>
185 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
186 <html xmlns="http://www.w3.org/1999/xhtml">
187 <head>
188 <title><?php echo $title?$title:'Megatokyo Administration Editor'; ?></title>
189 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
190 <style media="screen" type="text/css">
191 html {
192 background: #eee;
193 }
194 body {
195 background: #fff;
196 color: #000;
197 font-family: Georgia, "Times New Roman", Times, serif;
198 margin-left: 25%;
199 margin-right: 25%;
200 padding: .2em 2em;
201 }
202 h1 {
203 color: #006;
204 font-dize: 18px;
205 font-weight: lighter;
206 }
207 h2 {
208 font-size: 16px;
209 }
210 p, li, dt {
211 line-height: 140%;
212 padding-bottom: 2px;
213 }
214 ul, ol {
215 padding: 5px 5px 5px 20px;
216 }
217 #logo {
218 margin-bottom: 2em;
219 }
220 -->
221 </style>
222 </head>
223 <body>
224 <h1 id="Logo">Megatokyo Admin</h1>
225 <?php if($title) echo "<h2>$title</h2>\n"; ?>
226 <p><?php echo $message; ?></p>
227 </body>
228 </html>
229 <?php
230 die();
231
232 }
233
234 function numeric_entities($string){
235 $mapping = array();
236 foreach (get_html_translation_table(HTML_ENTITIES, ENT_QUOTES) as $char => $entity){
237 $mapping[$entity] = '&#' . ord($char) . ';';
238 }
239 return str_replace(array_keys($mapping), $mapping, $string);
240 }
241
242 function utfentities($string)
243 {
244 return htmlentities($string, ENT_COMPAT, 'UTF-8');
245 }
246
247 ?>
@@ -0,0 +1,57
1 <?php
2
3 function getimagefromfile($filename)
4 {
5 $img_data = getimagesize($filename);
6 $ext = image_type_to_extension($img_data[2]);
7
8 switch($ext)
9 {
10 case '.gif':
11 return imagecreatefromgif($filename);
12 break;
13 case '.jpg':
14 case '.jpeg':
15 return imagecreatefromjpeg($filename);
16 break;
17 case '.png':
18 return imagecreatefrompng($filename);
19 break;
20 default:
21 return false;
22 }
23 }
24
25 function crop_resize($filename, $dest_file)
26 {
27 #REQUIRES: image be at least 300x245
28 $source = getimagefromfile($filename);
29 if(!$source)
30 {
31 return false;
32 }
33 $dest = imagecreatetruecolor(300, 245);
34
35 #attempt to determine scaling factor
36 $data = getimagesize($filename);
37 #300x245 reduces to 60x49
38 $factor = min(floor($data[0]/60), floor($data[1]/49));
39 #well, that should give us a good scaling factor
40
41 #now we have to determine what point to start from
42 $src_x = floor(($data[0]/2) - ($factor*30));
43 $src_y = floor(($data[1]/2) - ($factor*24.5));
44
45 #make sure we don't fuck things up
46 if($src_x < 0) $src_x=0;
47 if($src_y < 0) $src_y=0;
48
49 #now resample
50 imagecopyresampled($dest, $source, 0, 0, $src_x, $src_y, 300, 245, $factor*60, $factor*49);
51 #and output
52 imagepng($dest, $dest_file);
53
54 return true;
55 }
56
57 ?>
@@ -0,0 +1,51
1 <?php
2
3
4 class MysqlStore {
5 var $link;
6 function connect($server,$user,$pass,$dbname) {
7 $this->link = @mysql_connect($server, $user, $pass)
8 or mtdie('Could not connect to the database server.');
9 @mysql_select_db($dbname, $this->link)
10 or mtdie('Could not open the megatokyo database.');
11 if( !$this->link ) mtdie('Could not connect to the database server.');
12 }
13
14
15 function query($sql, $showerror = true ) {
16 $r = mysql_query( $sql, $this->link );
17 if( false === $r && $showerror ) echo mysql_error();
18 return $r;
19 }
20
21 function getAll($sql) {
22 if( $r = $this->query( $sql ) ) {
23 $ret = array();
24 while( $row = mysql_fetch_object( $r ) ) {
25 $ret[] = $row;
26 }
27 return $ret;
28 }
29 }
30
31 function getRow($sql) {
32 if( $r = $this->query( $sql ) ) {
33 if( false === $r ) {
34 echo mysql_error();
35 return false;
36 }
37 if( mysql_num_rows( $r ) == 0 ) return false;
38 return mysql_fetch_object( $r );
39 }
40 }
41
42 function getOne($sql) {
43 if( $r = $this->query( $sql ) ) {
44 if( mysql_num_rows( $r ) == 0 ) return false;
45 $ret = mysql_fetch_row( $r );
46 return $ret[0];
47 }
48 }
49 }
50
51 ?> No newline at end of file
@@ -0,0 +1,134
1 <?php
2
3
4 function check_nonce($action) {
5 if( !verify_nonce($_REQUEST['_mtnonce'], $action) ) {
6 wp_nonce_ays($action);
7 }
8 }
9
10 /*
11 Use nonce lifetime of 20 minutes.
12 2 time slices, 10 minutes long each.
13 Older nonces will trigger AYS
14 */
15
16 if ( !function_exists('verify_nonce') ) :
17 function verify_nonce($nonce, $action = -1) {
18 global $currentuser;
19 $uid = (int) $currentuser->id;
20
21 $i = ceil(time() / 600);
22
23 //Allow for expanding range, but only do one check if we can
24 if( substr( md5($i . '|' . $action . $uid), -12, 10) == $nonce || substr( md5(($i - 1) . '|' . $action . $uid), -12, 10) == $nonce )
25 return true;
26 return false;
27 }
28 endif;
29
30 if ( !function_exists('create_nonce') ) :
31 function create_nonce($action = -1) {
32 global $currentuser;
33 $uid = (int) $currentuser->id;
34
35 $i = ceil(time() / 600);
36
37 return substr( md5($i . '|' . $action . $uid), -12, 10);
38 }
39 endif;
40
41
42 function wp_nonce_ays($action) {
43 if ( preg_match('#([^/]+\.php)$#', $_SERVER["PHP_SELF"], $self_matches) ) {
44 $pagenow = $self_matches[1];
45 } elseif ( strpos($_SERVER["PHP_SELF"], '?') !== false ) {
46 $pagenow = explode('/', $_SERVER["PHP_SELF"]);
47 $pagenow = trim($pagenow[(sizeof($pagenow)-1)]);
48 $pagenow = explode('?', $pagenow);
49 $pagenow = $pagenow[0];
50 } else {
51 $pagenow = 'index.php';
52 }
53
54 $adminurl = clean_url(wp_get_referer());
55
56 $html='The attempted operation is potentially unsafe.</p>';
57
58 if ( $_POST ) {
59 $q = http_build_query($_POST);
60 $q = explode( ini_get('arg_separator.output'), $q);
61 $html .= "\t<form method='post' action='" . htmlentities($pagenow) . "'>\n";
62 foreach ( (array) $q as $a ) {
63 $v = substr(strstr($a, '='), 1);
64 $k = substr($a, 0, -(strlen($v)+1));
65 $html .= "\t\t<input type='hidden' name='" . mt_specialchars(urldecode($k),true) . "' value='" . mt_specialchars(urldecode($v),true) . "' />\n";
66 }
67 $html .= "\t\t<input type='hidden' name='_mtnonce' value='" . create_nonce($action) . "' />\n";
68 $html .= "\t\t<div id='message' class='confirm fade'>\n\t\t<p>" . mt_explain_nonce($action) . "</p>\n\t\t<p><a href='$adminurl'>No</a> &nbsp; <input type='submit' value='Yes' /></p>\n\t\t</div>\n\t</form><p>\n";
69 } else {
70 $html .= "\t<div id='message' class='confirm fade'>\n\t<p>" . mt_explain_nonce($action) . "</p>\n\t<p><a href='$adminurl'>No</a> &nbsp; <a href='" . clean_url(add_query_arg( '_mtnonce', create_nonce($action), $_SERVER['REQUEST_URI'] )) . "'>Yes</a></p>\n\t</div><p>\n";
71 }
72 mtdie($html, 'Are You Sure?');
73 }
74
75 function mt_explain_nonce($action) {
76 global $mtdb;
77 $c = explode('-',$action);
78 $i = (int)$c[2];
79
80 $message = array();
81 $message['rant']['new'] = 'Are you sure you want to create a new rant?';
82 $message['rant']['save'] = 'Are you sure you want to save changes to the rant "%s"?';
83 $message['rant']['delete'] = 'Are you sure you want to delete the rant "%s"? This is a destructive action, and cannot be undone!';
84
85 $message['type']['new'] = 'Are you sure you want to create a new type?';
86 $message['type']['save'] = 'Are you sure you want to save changes to the type "%s"?';
87 $message['type']['delete'] = 'Are you sure you want to delete the type "%s"? This is a destructive action, and cannot be undone!';
88
89 $message['metatype']['new'] = 'Are you sure you want to create a new metatype?';
90 $message['metatype']['save'] = 'Are you sure you want to save changes to the metatype "%s"?';
91 $message['metatype']['delete'] = 'Are you sure you want to delete the metatype "%s"? This is a destructive action, and cannot be undone!';
92
93 $message['strip']['new'] = 'Are you sure you want to create a new strip?';
94 $message['strip']['save'] = 'Are you sure you want to save changes to the strip "%s"?';
95 $message['strip']['delete'] = 'Are you sure you want to delete the comic strip "%1$s"? This will break site navigation, which can be fixed by changing other strip numbers. This is a destructive action, and cannot be undone! It is far better to <a href="edit-comic.php?strip_id=%1$s">edit the existing strip</a>.';
96 $message['strip']['swap'] = 'Are you sure you want to swap these two strips? This is a destructive action, and cannot be undone!';
97
98 $message['statusbox']['update'] = 'Are you sure you want to update the statusbox information?';
99 $message['scratchpad']['new'] = 'Are you sure you want to update the scratchpad information?';
100 $message['twitter']['new'] = 'Are you sure you want to update the Twitter feed?';
101
102 $message['extra']['new'] = 'Are you sure you want to upload a new file to /extra?';
103 $message['extra']['delete'] = 'Are you sure you want to delete the file from /extra named "%s"?';
104
105 $message['twitteruser']['delete'] = 'Are you sure you want to delete the twitter user "%s"?';
106
107 if( isset( $message[ $c[1] ][ $c[0] ] )) {
108 $t = $message[ $c[1] ][ $c[0] ];
109
110 if( false !== strpos( $t, '%' ) ) {
111
112 switch( $c[1] ) {
113 case 'rant': $v = $mtdb->getOne('SELECT title FROM rant WHERE id=' . $i); break;
114 case 'strip': $v = $mtdb->getOne('SELECT id FROM strip WHERE id=' . $i); break;
115 case 'type': $v = $mtdb->getOne('SELECT name FROM strip_t WHERE id=' . $i); break;
116 case 'metatype':$v = $mtdb->getOne('SELECT name FROM meta_t WHERE id=' . $i); break;
117 case 'extra': $temp = extra_file_from_inode($i); $v = $temp->name; break;
118 case 'twitteruser': $v = $mtdb->getOne('SELECT username FROM twitter_user WHERE id=' . $i); break;
119 default: $v = $i;
120 }
121
122 return sprintf( $t, mt_specialchars($v,true) );
123 }
124
125 return $t;
126 }
127 return "Are you sure you want to perform the action $action?";
128 }
129
130 function nonce_field($action) {
131 echo '<input type="hidden" name="_mtnonce" value="' . create_nonce($action) . '" />';
132 }
133
134 ?> No newline at end of file
@@ -0,0 +1,53
1 <?php
2
3 class Page {
4 var $url_name, $status, $title, $body, $style;
5 }
6
7 function savepage($page) {
8 if($page->url_name)
9 return updatepage($page);
10 else
11 return insertpage($page);
12 }
13
14 function insertpage($page) {
15 global $mtdb;
16 $sql = 'INSERT INTO static_page ( url_name, status, title, body, style ) VALUES ('
17 . ' "' . mysql_real_escape_string($page->url_name)
18 . '", "' . mysql_real_escape_string($page->status)
19 . '", "' . mysql_real_escape_string( trim( $page->title ) )
20 . '", "' . mysql_real_escape_string( trim( $page->body ) )
21 . '", "' . mysql_real_escape_string( trim( $page->style ) )
22 . '")';
23 adminlog("Page '".$page->url_name."' has been added.", MTS_PAGE, MTA_ADD);
24 return $mtdb->query($sql);
25 }
26
27 function updatepage($page) {
28 if ( !$page->url_name ) return false;
29 global $mtdb;
30
31 $sql = 'UPDATE static_page SET url_name = "' . mysql_real_escape_string($page->url_name)
32 . '", status = "' . mysql_real_escape_string($page->status)
33 . '", title = "' . mysql_real_escape_string( trim($page->title) )
34 . '", body = "' . mysql_real_escape_string( trim($page->body ) )
35 . '", style = "' . mysql_real_escape_string( trim($page->style ) )
36 . '" WHERE url_name = "' . mysql_real_escape_string($page->url_name) . '"';
37 adminlog("Page '".$page->url_name."' has been updated.", MTS_PAGE, MTA_MODIFY);
38 return $mtdb->query( $sql );
39 }
40
41 function deletepage($url_name) {
42 if ( !$url_name ) return false;
43 global $mtdb;
44 adminlog("Page '".$page->url_name."' has been deleted.", MTS_PAGE, MTA_DELETE);
45 return $mtdb->query( 'DELETE FROM static_page WHERE url_name = "' . mysql_real_escape_string($url_name) . '"' );
46 }
47
48 function getpage($url_name) {
49 global $mtdb;
50 return $mtdb->getRow( 'SELECT url_name, status, title, body, style FROM static_page WHERE url_name = "'. mysql_real_escape_string($url_name) . '"' );
51 }
52
53 ?>
@@ -0,0 +1,9
1 function new_rant_attachment()
2 {
3 var list = document.getElementById('rant_attachment_list');
4
5 var elt = document.createElement('li');
6 elt.innerHTML = '<input type="file" name="rant_attachment[]" />';
7
8 list.appendChild(elt);
9 }
@@ -0,0 +1,119
1 <?php
2
3 class Rant {
4 var $id, $published, $status, $side, $author, $title, $body, $link, $imagetype, $imagetext;
5 }
6
7 function saverant($rant) {
8 if($rant->id)
9 return updaterant($rant);
10 else
11 return insertrant($rant);
12 }
13
14 function insertrant($rant) {
15 global $mtdb;
16 $sql = 'INSERT INTO rant ( published, status, side, author, title, body, link, imagetype, imagetext ) VALUES ( FROM_UNIXTIME('
17 . (int)$rant->published
18 . '), "' . mysql_real_escape_string($rant->status)
19 . '", "' . mysql_real_escape_string($rant->side)
20 . '", "' . (int)$rant->author
21 . '", "' . mysql_real_escape_string( trim( $rant->title) )
22 . '", "' . mysql_real_escape_string( trim( $rant->body ) )
23 . '", "' . mysql_real_escape_string( trim( $rant->link ) )
24 . '", ' . mysql_real_escape_string($rant->imagetype)
25 . ', "' . mysql_real_escape_string( trim( $rant->imagetext ) )
26 . '")';
27
28 if( $mtdb->query( $sql ) ) {
29 //logthis( 'Saved changes to rant ' . $rant->id );
30 $rant->id = mysql_insert_id( $mtdb->link );
31
32 adminlog("Rant ".$rant->id." saved.", MTS_RANT, MTA_ADD);
33
34 if($rant->status == "published")
35 {
36 $poster = get_userdatabyid($rant->author);
37 adminlog("Rant ".$rant->id." published.", MTS_RANT, MTA_ADD);
38 twitterpost("New rant posted by ".$poster->name.": ".SITE_HOST.SITE_PATH."/rant/".$rant->id);
39
40 if($rant->author === 1) {
41 tumblrpost($rant->title, $rant->body);
42 }
43 }
44
45 return $rant->id;
46 }
47 return false;
48 }
49
50 function updaterant($rant) {
51 if ( !(int)$rant->id ) return false;
52 global $mtdb;
53
54 #first, check if it's published already
55 $qr = $mtdb->query("SELECT status FROM rant WHERE id = ".$rant->id);
56 $row = mysql_fetch_row($qr);
57 $status = $row[0];
58
59 adminlog("Rant ".$rant->id." updated.", MTS_RANT, MTA_UPDATE);
60
61 $sql = 'UPDATE rant SET published=FROM_UNIXTIME(' . (int)$rant->published
62 . '), status = "' . mysql_real_escape_string($rant->status)
63 . '", side = "' . mysql_real_escape_string($rant->side)
64 . '", author = ' . (int)$rant->author
65 . ', title = "' . mysql_real_escape_string( trim($rant->title) )
66 . '", body = "' . mysql_real_escape_string( trim($rant->body ) )
67 . '", link = "' . mysql_real_escape_string( trim($rant->link ) )
68 . '", imagetype = ' . (int)$rant->imagetype
69 . ', imagetext = "' . mysql_real_escape_string( trim($rant->imagetext) )
70 . '" WHERE id=' . (int)$rant->id;
71
72 if($status == "draft" && $rant->status == "published")
73 {
74 $poster = get_userdatabyid($rant->author);
75 adminlog("Rant ".$rant->id." published.", MTS_RANT, MTA_UPDATE);
76 twitterpost("New rant posted by ".$poster->name.": ".SITE_HOST.SITE_PATH."/rant/".$rant->id);
77
78 if($rant->author === 1) {
79 tumblrpost($rant->title, $rant->body);
80 }
81 }
82
83 return $mtdb->query( $sql );
84 }
85
86 function deleterant($rantid) {
87 if ( !(int)$rantid ) return false;
88 global $mtdb;
89 adminlog("Rant ".$rantid." deleted.", MTS_RANT, MTA_DELETE);
90 return $mtdb->query( 'DELETE FROM rant WHERE id=' . $rantid );
91 }
92
93 function deleteattachment($id)
94 {
95 global $mtdb;
96 $file = SITE_PATH_ABS.'/'.get_rantattachment_filename($id);
97 unlink( $file ) or adminlog("Could not delete $file", MTS_RANT, MTA_DELETE, E_USER_WARNING);
98 $mtdb->query( 'DELETE FROM rant_attachment WHERE id = ' . $id );
99 adminlog("Deleted attachment $id", MTS_RANT, MTA_DELETE);
100 }
101
102 function getrant($id) {
103 global $mtdb;
104 return $mtdb->getRow( 'SELECT id, UNIX_TIMESTAMP(published) as published, status, side, author, title, body, link, imagetype, imagetext FROM rant WHERE id = '. (int)$id );
105 }
106
107 function get_rantimage_filename( $rant ) {
108 global $mtdb;
109 $ext = $mtdb->getOne( 'SELECT extension FROM media_t WHERE id=' . (int)$rant->imagetype ); // filename extension
110 return sprintf( '%s/%04d.%s',SITE_RANT, (int)$rant->id, $ext );
111 }
112
113 function get_rantattachment_filename( $id ) {
114 global $mtdb;
115 $ext = $mtdb->getOne( 'SELECT extension FROM media_t JOIN rant_attachment ra ON ra.media = media_t.id WHERE ra.id=' . (int)$id ); // filename extension
116 return sprintf( '%s/%d.%s',SITE_RANT_ATTACHMENT, (int)$id, $ext );
117 }
118
119 ?>
@@ -0,0 +1,14
1 <?php
2
3 function rsspost($body, $url)
4 {
5 global $mtdb;
6
7 $mtdb->query('INSERT INTO rss_comment (body, url)
8 VALUES ("'.mysql_real_escape_string($body).'",
9 "'.mysql_real_escape_string($url).'")');
10
11 return true;
12 }
13
14 ?>
@@ -0,0 +1,130
1 <?php
2
3 // Book: The offset from 0 at the beginning of time
4 // Page: The offset from 0 at the beginning of the volume
5
6 class Strip {
7 var $id, $old_id, $published, $media, $type, $title, $book, $page;
8 }
9
10 // old_id is used to detect alterations to the strip id in forms. Not saved in database.
11 // media is imagetype
12
13 // Strip id is automatically incremented
14 function insertstrip(&$strip) {
15 global $mtdb;
16
17 $strip->book = ($strip->book == '') ? 'NULL' : (int)$strip->book;
18 $strip->page = ($strip->page == '') ? 'NULL' : (int)$strip->page;
19
20 $mtdb->query('START TRANSACTION');
21 $newid = $mtdb->getOne('SELECT MAX(id) FROM strip') + 1;
22 $sql = 'INSERT INTO strip ( id, published, media, type, title, book, page ) VALUES ('
23 . $newid
24 . ', FROM_UNIXTIME(' . (int)$strip->published
25 . '), '. (int)$strip->media
26 . ', ' . (int)$strip->type
27 . ', "' . mysql_real_escape_string( trim($strip->title) )
28 . '", '. $strip->book
29 . ', ' . $strip->page
30 . ')';
31
32 $r = $mtdb->query( $sql );
33 if( !$r ) {
34 $mtdb->query('ROLLBACK');
35 return false;
36 }
37 $mtdb->query('COMMIT');
38 adminlog("Comic ".$newid." posted.", MTS_STRIP, MTA_ADD);
39
40 $strip->id = $newid;
41 if( $strip->id == 0 ) return false;
42 return true;
43 }
44
45 function updatestrip(&$strip) {
46 global $mtdb;
47
48 $strip->book = ($strip->book === '') ? 'NULL' : (int)$strip->book;
49 $strip->page = ($strip->page === '') ? 'NULL' : (int)$strip->page;
50
51 $mtdb->query('START TRANSACTION');
52 $sql = 'UPDATE strip SET
53 published = FROM_UNIXTIME(' . (int)$strip->published .')
54 , media = '. (int)$strip->media .'
55 , type = ' . (int)$strip->type .'
56 , title = "' . mysql_real_escape_string( trim($strip->title) ) .'"
57 , book = ' . (int)$strip->book .'
58 , page = ' . (int)$strip->page .'
59 WHERE id = ' . (int)$strip->id;
60 $mtdb->query( $sql );
61 $mtdb->query('COMMIT');
62 adminlog("Comic ".$strip->id." modified.", MTS_STRIP, MTA_MODIFY);
63 return true;
64 }
65
66 // Delete destination strip from DB and FS, and Update/Rename the source strip into place. Destructive Move!
67 function move_strip($from_id, $to_id)
68 {
69 global $mtdb;
70 $from_id = (int) $from_id;
71 $to_id = (int) $to_id;
72
73 // Ensure our source exists
74 $num_strips = $mtdb->getOne( "SELECT COUNT(*) FROM strip WHERE id = $from_id" );
75 if($num_strips < 1)
76 mtdie("Cannot move strip number $from_id, because it cannot be found in database.");
77
78 // Ready the destination
79 deletestrip( $to_id );
80
81 // Update database
82 $mtdb->query( "UPDATE strip SET id = $to_id WHERE id = $from_id" );
83 $strip = $mtdb->getRow( "SELECT strip.id, extension FROM strip, media_t WHERE media_t.id = strip.media AND strip.id = $to_id" );
84
85 // Update filesystem
86 foreach(glob(sprintf(SITE_PATH_ABS.'/'.SITE_STRIP.'/%04d.*', $from_id)) as $item) {
87 preg_match('/\.(\w{3})$/', $item, $match) or die("Invalid filename: $item");
88 rename($item, sprintf(SITE_PATH_ABS.'/'.SITE_STRIP.'/%04d.%s', $to_id, $match[1]));
89 }
90 }
91
92 // Classic swap function, using strip 0 as temporary storage. Can cause concurrency issues. FLOCK!
93 function swap_strips( $from_id, $to_id ) {
94 move_strip($from_id, 0);
95 move_strip($to_id, $from_id);
96 move_strip(0, $from_id );
97 adminlog("Comics ".$from_id." and ".$to_id." swapped.", MTS_STRIP, MTA_MODIFY);
98 }
99
100 function deletestrip($id) {
101 $id = (int)$id;
102 if ( !$id ) return false;
103
104 global $mtdb;
105 $r = $mtdb->query( 'DELETE FROM strip WHERE id=' . $id );
106 foreach(glob(sprintf(SITE_PATH_ABS.'/'.SITE_STRIP.'/%04d*.*', $id)) as $item)
107 unlink($item);
108 foreach(glob(sprintf(SITE_PATH_ABS.'/'.SITE_STRIP.'/restricted/%04d*.*', $id)) as $item)
109 unlink($item);
110 adminlog("Comic ".$id." deleted.", MTS_STRIP, MTA_DELETE);
111 return $r;
112 }
113
114 function getstrip($id) {
115 global $mtdb;
116 return $mtdb->getRow( 'SELECT id, UNIX_TIMESTAMP(published) as published, type, media, title, book, page FROM strip WHERE id=' . (int)$id);
117 }
118
119 function get_stripimage_filename( $strip ) {
120 global $mtdb;
121 $ext = $mtdb->getOne( 'SELECT extension FROM media_t WHERE id=' . (int)$strip->media ); // filename extension
122 return sprintf( '%s/%04d.%s', SITE_STRIP, $strip->id, $ext );
123 }
124
125 function get_stripid_by_rantid($rantid) {
126 global $mtdb;
127 return $mtdb->getOne('SELECT MAX(strip.id) FROM strip,rant WHERE strip.published<=rant.published AND rant.id=' . (int)$rantid);
128 }
129
130 ?>
@@ -0,0 +1,182
1 <?php
2 //check that angle brackets are balanced
3 function bracketbalance($line)
4 {
5 #first, if no angle brackets, we're OK
6 if(substr_count($line, "<") == 0 && substr_count($line, ">") == 0)
7 return true;
8
9 if(substr_count($line, "<") != substr_count($line, ">"))
10 {
11 return false;
12 }
13
14 return true;
15 }
16
17 // Retrieve transcript for this strip from the database, modifying the strip object.
18 function gettranscript(&$strip)
19 {
20 global $mtdb;
21
22 $result = $mtdb->query('SELECT strip FROM transcript WHERE strip=' . (int)$strip->id );
23
24 if($result)
25 {
26 $output = '';
27 /*
28 #this gets me the highest panel number that has a transcript
29 # panels beyond that either lack speech or don't exist
30 # either way, I care not
31 Might be able to exchange this loop of getOne()s for a getAll() call.
32 */
33 $numPanels = $mtdb->getOne( 'SELECT MAX(panel) FROM transcript WHERE transcript.strip=' . (int)$strip->id );
34 if( $numPanels ) {
35 for($i = 1; $i <= $numPanels; $i++) {
36 $result = $mtdb->query( 'SELECT speaker, speech FROM transcript WHERE transcript.strip=' . (int)$strip->id . ' AND panel=' .$i.' ORDER BY line')
37 or mtdie("There was an error fetching the panel count in the transcript for $strip->id, panel $i. " . mysql_error(), 'SQL Error');
38
39 if(!$result) continue;
40
41 $output.= "\nnewpanel\n";
42 while($row = mysql_fetch_row($result)) {
43 if(strlen($row[0]) < 1) continue;
44
45 $output.= $row[0];
46 if($row[1] !== '') $output.= ":: ".$row[1];
47 $output.= "\n";
48 }
49 }
50 }
51 }
52 $strip->transcript = $output;
53 return $output;
54 }
55
56
57 // Parse submitted transcript from strip object, and insert it into the database.
58 function savetranscript( &$strip ) {
59 global $mtdb;
60 $info = '';
61
62 $mtdb->query('START TRANSACTION');
63
64 //remove any old transcript data - it's being replaced
65 $mtdb->query( 'DELETE FROM transcript WHERE transcript.strip=' . (int)$strip->id );
66
67 if( $strip->transcript_posted ) {
68 $inserter = 'INSERT INTO transcript (strip,panel,line,speaker,speech,search) VALUES (%d,%d,%d,"%s","%s","%s")';
69
70 if(strpos($strip->transcript_posted, 'Panel <$n>') !== FALSE) {
71 # This is probably a scrivener script
72
73 $panels = explode('Panel <$n>', $strip->transcript_posted);
74 $panels = array_map('trim', $panels);
75 $numPanels = count($panels);
76
77 for($i = 0; $i < $numPanels; $i++) {
78 $lines = explode("\n", $panels[$i]);
79 $lines = array_map('trim', $lines);
80
81 # Initialize speaker controls
82 $speaker = null;
83 $has_spoken = true;
84
85 for($j = 0; $j < count($lines); $j++) {
86 $insert_sql = '';
87
88 if(strpos($lines[$j], '(') === 0) {
89 # Line is a note, add it as a comment
90 $insert_sql = sprintf($inserter, (int)$strip->id, $i, $j, '#', mysql_real_escape_string($lines[$j]), '');
91 } elseif(strpos($lines[$j], '[') === 0 || strlen($lines[$j]) == 0) {
92 # Line is an annotation or blank, do nothing
93 continue;
94 } elseif(strpos($lines[$j], 'nospeaking:') === 0) {
95 # Line contains a list of nonspeaking characters
96 array_splice($lines, $j, 1, array_map('_nospeaker', explode(',', substr($lines[$j], 11))));
97 $speaker = trim(substr($lines[$j], 11));
98 $insert_sql = sprintf($inserter, (int)$strip->id, $i, $j, mysql_real_escape_string($speaker), '', '');
99 } elseif($i > 0 && $lines[$j] == strtoupper($lines[$j])) {
100 # Line designates a new speaker, note speaker
101
102 # Handle speakers who did not say anything
103 if(null !== $speaker && !$has_spoken)
104 $insert_sql = sprintf($inserter, (int)$strip->id, $i, $j, mysql_real_escape_string($speaker), '', '');
105
106 $speaker = ucfirst(strtolower($lines[$j]));
107 $has_spoken = false;
108 } elseif(null !== $speaker) {
109 # Line is speech, match with speaker and add
110 if(!bracketbalance($lines[$j]))
111 $info .= "<p>Warning: Open brackets do not match close brackets in panel $i for speaker ".htmlentities($speaker).'</p>';
112
113 $search = preg_replace( '/[[:punct:]]|(?<=\s)\s+/', ' ', strtolower($lines[$j]) );
114 $insert_sql = sprintf($inserter, (int)$strip->id, $i, $j, mysql_real_escape_string($speaker),
115 mysql_real_escape_string($lines[$j]), mysql_real_escape_string($search));
116 $has_spoken = true;
117 } else {
118 # Line is unrecognized, add it as a comment
119 $insert_sql = sprintf($inserter, (int)$strip->id, $i, $j, '#', mysql_real_escape_string($lines[$j]), '');
120 }
121
122 if( $insert_sql && false === $mtdb->query( $insert_sql ) ) {
123 $mtdb->query('ROLLBACK');
124 mtdie (mysql_error(), 'Error inserting transcript.');
125 }
126 }
127
128 if(null !== $speaker && !$has_spoken) {
129 $insert_sql = sprintf($inserter, (int)$strip->id, $i, $j, mysql_real_escape_string($speaker), '', '');
130 if( false === $mtdb->query( $insert_sql ) ) {
131 $mtdb->query('ROLLBACK');
132 mtdie (mysql_error(), 'Error inserting transcript.');
133 }
134 }
135 }
136
137 } else {
138 # Assume that this is a Kalium style transcript
139
140 $panels = explode('newpanel', $strip->transcript_posted);
141 $numPanels = count($panels);
142 foreach($panels as $currPanel)
143 $currPanel = trim($currPanel);
144
145 for($i = 1; $i < $numPanels; $i++) {
146 $lines = explode("\n", $panels[$i]);
147 $numLines = count($lines);
148 foreach($lines as $currLine)
149 $currLine = trim($currLine);
150
151 for($j = 1; $j < $numLines; $j++) {
152 $spoken = explode("::", $lines[$j]); // Distinguish between speaker and speech
153
154 $spoken[0] = trim($spoken[0]); // Strip excess whitespace
155 $spoken[1] = trim($spoken[1]);
156
157 if(strlen($spoken[0]) < 1) continue; // Disregard null
158 $spoken[2] = preg_replace('/[[:punct:]]|(?<=\s)\s+/', ' ', strtolower($spoken[1]) ); // Make searchable text
159
160 if(!bracketbalance($spoken[1]))
161 $info .= "<p>Warning: Open brackets do not match close brackets in panel $i for speaker ".htmlentities($spoken[0]).'</p>';
162
163 $insert_sql = sprintf($inserter, (int)$strip->id, (int)$i, (int)$j, mysql_real_escape_string($spoken[0]),
164 mysql_real_escape_string($spoken[1]), mysql_real_escape_string($spoken[2]) );
165 if( false === $mtdb->query( $insert_sql ) ) {
166 $mtdb->query('ROLLBACK');
167 mtdie (mysql_error(), 'Error inserting transcript.');
168 }
169 }
170 }
171 }
172 }
173 $mtdb->query('COMMIT');
174 return $info;
175 }
176
177 function _nospeaker($name)
178 {
179 return "nospeaking: $name";
180 }
181
182 ?>
@@ -0,0 +1,50
1 <?php
2
3 function tumblrpost($title, $body) {
4 global $error;
5 // Authorization info
6 $tumblr_email = TUMBLR_USER;
7 $tumblr_password = TUMBLR_PASS;
8
9 // Data for new record
10 $post_type = 'regular';
11 $post_title = $title;
12 $post_body = $body;
13
14 // Prepare POST request
15 $request_data = http_build_query(
16 array(
17 'email' => $tumblr_email,
18 'password' => $tumblr_password,
19 'type' => $post_type,
20 'title' => $post_title,
21 'body' => $post_body,
22 'generator' => 'Megatokyo',
23 'format' => 'html',
24 'tags' => 'rant',
25 )
26 );
27
28 // Send the POST request (with cURL)
29 $c = curl_init('http://www.tumblr.com/api/write');
30 curl_setopt($c, CURLOPT_POST, true);
31 curl_setopt($c, CURLOPT_POSTFIELDS, $request_data);
32 curl_setopt($c, CURLOPT_RETURNTRANSFER, true);
33 $result = curl_exec($c);
34 $status = curl_getinfo($c, CURLINFO_HTTP_CODE);
35 curl_close($c);
36
37 // Check for success
38 if ($status == 201) {
39 $info .= "<p>Successfully posted to Tumblr.</p>";
40 adminlog("Post to Tumblr successful. Post id $result", MTS_TUMBLR, MTA_ADD);
41 } else if ($status == 403) {
42 $error .= '<p>Bad email or password posting to Tumblr.</p>';
43 adminlog('Bad email or password posting to Tumblr.', MTS_TUMBLR, MTA_ADD);
44 } else {
45 $error .= "<p>There was an error posting to Tumblr.</p>";
46 adminlog("Error posting to Tumblr: $result", MTS_TUMBLR, MTA_ADD);
47 }
48 }
49
50 ?>
@@ -0,0 +1,63
1 <?php
2
3 function twitterpost($message, $user=TWITTER_USER, $password=TWITTER_PASS)
4 {
5 global $mtdb, $info, $error;
6 if( $user == '' ) {
7 # preserve existing twitterpost(message) style posting until OAuth has been vetted.
8 $user = TWITTER_USER;
9 $curl_handle = curl_init();
10 curl_setopt($curl_handle, CURLOPT_URL, TWITTER_HOST);
11 curl_setopt($curl_handle, CURLOPT_CONNECTTIMEOUT, 2);
12 curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, 1);
13 curl_setopt($curl_handle, CURLOPT_POST, 1);
14 curl_setopt($curl_handle, CURLOPT_POSTFIELDS, "status=".urlencode($message));
15 curl_setopt($curl_handle, CURLOPT_USERPWD, urlencode($user).":".urlencode($password));
16
17 $buffer = curl_exec($curl_handle);
18 curl_close($curl_handle);
19
20 if(empty($buffer))
21 {
22 adminlog("Twitter post failed for user $user!", MTS_TWITTER, MTA_ADD);
23 }
24 return !empty($buffer);
25
26 } else {
27 # OAuth Mode
28 $row = $mtdb->getRow( sprintf('SELECT id, username, oauth_token, oauth_token_secret FROM twitter_user WHERE username="%s"', mysql_real_escape_string($user)));
29
30 $username = $row->username;
31 $oauth_token = $row->oauth_token;
32 $oauth_token_secret = $row->oauth_token_secret;
33
34 $connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, $oauth_token, $oauth_token_secret);
35
36 $parameters = array('status' => $message );
37 $status = $connection->post('statuses/update', $parameters);
38
39 switch( $connection->http_code ) {
40 case 200:
41 adminlog("Twitter post succeeded for user $username!", MTS_TWITTER, MTA_ADD);
42 return true;
43 default:
44 adminlog("Twitter post failed for user $username!", MTS_TWITTER, MTA_ADD);
45 return false;
46 }
47
48
49 }
50
51
52 }
53
54
55 function setOAuthTokens($userid,$oauth_token,$oauth_token_secret, $username) {
56 global $mtdb;
57 $id = (int)$userid;
58 if( $mtdb->query( sprintf('UPDATE twitter_user SET oauth_token="%s", oauth_token_secret="%s", username="%s" WHERE id=%d', mysql_real_escape_string($oauth_token), mysql_real_escape_string($oauth_token_secret), mysql_real_escape_string($username), $id )) )
59 return true;
60 return false;
61 }
62
63 ?>
This diff has been collapsed as it changes many lines, (874 lines changed) Show them Hide them
@@ -0,0 +1,874
1 <?php
2 // vim: foldmethod=marker
3
4 /* Generic exception class
5 */
6 class OAuthException extends Exception {
7 // pass
8 }
9
10 class OAuthConsumer {
11 public $key;
12 public $secret;
13
14 function __construct($key, $secret, $callback_url=NULL) {
15 $this->key = $key;
16 $this->secret = $secret;
17 $this->callback_url = $callback_url;
18 }
19
20 function __toString() {
21 return "OAuthConsumer[key=$this->key,secret=$this->secret]";
22 }
23 }
24
25 class OAuthToken {
26 // access tokens and request tokens
27 public $key;
28 public $secret;
29
30 /**
31 * key = the token
32 * secret = the token secret
33 */
34 function __construct($key, $secret) {
35 $this->key = $key;
36 $this->secret = $secret;
37 }
38
39 /**
40 * generates the basic string serialization of a token that a server
41 * would respond to request_token and access_token calls with
42 */
43 function to_string() {
44 return "oauth_token=" .
45 OAuthUtil::urlencode_rfc3986($this->key) .
46 "&oauth_token_secret=" .
47 OAuthUtil::urlencode_rfc3986($this->secret);
48 }
49
50 function __toString() {
51 return $this->to_string();
52 }
53 }
54
55 /**
56 * A class for implementing a Signature Method
57 * See section 9 ("Signing Requests") in the spec
58 */
59 abstract class OAuthSignatureMethod {
60 /**
61 * Needs to return the name of the Signature Method (ie HMAC-SHA1)
62 * @return string
63 */
64 abstract public function get_name();
65
66 /**
67 * Build up the signature
68 * NOTE: The output of this function MUST NOT be urlencoded.
69 * the encoding is handled in OAuthRequest when the final
70 * request is serialized
71 * @param OAuthRequest $request
72 * @param OAuthConsumer $consumer
73 * @param OAuthToken $token
74 * @return string
75 */
76 abstract public function build_signature($request, $consumer, $token);
77
78 /**
79 * Verifies that a given signature is correct
80 * @param OAuthRequest $request
81 * @param OAuthConsumer $consumer
82 * @param OAuthToken $token
83 * @param string $signature
84 * @return bool
85 */
86 public function check_signature($request, $consumer, $token, $signature) {
87 $built = $this->build_signature($request, $consumer, $token);
88 return $built == $signature;
89 }
90 }
91
92 /**
93 * The HMAC-SHA1 signature method uses the HMAC-SHA1 signature algorithm as defined in [RFC2104]
94 * where the Signature Base String is the text and the key is the concatenated values (each first
95 * encoded per Parameter Encoding) of the Consumer Secret and Token Secret, separated by an '&'
96 * character (ASCII code 38) even if empty.
97 * - Chapter 9.2 ("HMAC-SHA1")
98 */
99 class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod {
100 function get_name() {
101 return "HMAC-SHA1";
102 }
103
104 public function build_signature($request, $consumer, $token) {
105 $base_string = $request->get_signature_base_string();
106 $request->base_string = $base_string;
107
108 $key_parts = array(
109 $consumer->secret,
110 ($token) ? $token->secret : ""
111 );
112
113 $key_parts = OAuthUtil::urlencode_rfc3986($key_parts);
114 $key = implode('&', $key_parts);
115
116 return base64_encode(hash_hmac('sha1', $base_string, $key, true));
117 }
118 }
119
120 /**
121 * The PLAINTEXT method does not provide any security protection and SHOULD only be used
122 * over a secure channel such as HTTPS. It does not use the Signature Base String.
123 * - Chapter 9.4 ("PLAINTEXT")
124 */
125 class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod {
126 public function get_name() {
127 return "PLAINTEXT";
128 }
129
130 /**
131 * oauth_signature is set to the concatenated encoded values of the Consumer Secret and
132 * Token Secret, separated by a '&' character (ASCII code 38), even if either secret is
133 * empty. The result MUST be encoded again.
134 * - Chapter 9.4.1 ("Generating Signatures")
135 *
136 * Please note that the second encoding MUST NOT happen in the SignatureMethod, as
137 * OAuthRequest handles this!
138 */
139 public function build_signature($request, $consumer, $token) {
140 $key_parts = array(
141 $consumer->secret,
142 ($token) ? $token->secret : ""
143 );
144
145 $key_parts = OAuthUtil::urlencode_rfc3986($key_parts);
146 $key = implode('&', $key_parts);
147 $request->base_string = $key;
148
149 return $key;
150 }
151 }
152
153 /**
154 * The RSA-SHA1 signature method uses the RSASSA-PKCS1-v1_5 signature algorithm as defined in
155 * [RFC3447] section 8.2 (more simply known as PKCS#1), using SHA-1 as the hash function for
156 * EMSA-PKCS1-v1_5. It is assumed that the Consumer has provided its RSA public key in a
157 * verified way to the Service Provider, in a manner which is beyond the scope of this
158 * specification.
159 * - Chapter 9.3 ("RSA-SHA1")
160 */
161 abstract class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod {
162 public function get_name() {
163 return "RSA-SHA1";
164 }
165
166 // Up to the SP to implement this lookup of keys. Possible ideas are:
167 // (1) do a lookup in a table of trusted certs keyed off of consumer
168 // (2) fetch via http using a url provided by the requester
169 // (3) some sort of specific discovery code based on request
170 //
171 // Either way should return a string representation of the certificate
172 protected abstract function fetch_public_cert(&$request);
173
174 // Up to the SP to implement this lookup of keys. Possible ideas are:
175 // (1) do a lookup in a table of trusted certs keyed off of consumer
176 //
177 // Either way should return a string representation of the certificate
178 protected abstract function fetch_private_cert(&$request);
179
180 public function build_signature($request, $consumer, $token) {
181 $base_string = $request->get_signature_base_string();
182 $request->base_string = $base_string;
183
184 // Fetch the private key cert based on the request
185 $cert = $this->fetch_private_cert($request);
186
187 // Pull the private key ID from the certificate
188 $privatekeyid = openssl_get_privatekey($cert);
189
190 // Sign using the key
191 $ok = openssl_sign($base_string, $signature, $privatekeyid);
192
193 // Release the key resource
194 openssl_free_key($privatekeyid);
195
196 return base64_encode($signature);
197 }
198
199 public function check_signature($request, $consumer, $token, $signature) {
200 $decoded_sig = base64_decode($signature);
201
202 $base_string = $request->get_signature_base_string();
203
204 // Fetch the public key cert based on the request
205 $cert = $this->fetch_public_cert($request);
206
207 // Pull the public key ID from the certificate
208 $publickeyid = openssl_get_publickey($cert);
209
210 // Check the computed signature against the one passed in the query
211 $ok = openssl_verify($base_string, $decoded_sig, $publickeyid);
212
213 // Release the key resource
214 openssl_free_key($publickeyid);
215
216 return $ok == 1;
217 }
218 }
219
220 class OAuthRequest {
221 private $parameters;
222 private $http_method;
223 private $http_url;
224 // for debug purposes
225 public $base_string;
226 public static $version = '1.0';
227 public static $POST_INPUT = 'php://input';
228
229 function __construct($http_method, $http_url, $parameters=NULL) {
230 @$parameters or $parameters = array();
231 $parameters = array_merge( OAuthUtil::parse_parameters(parse_url($http_url, PHP_URL_QUERY)), $parameters);
232 $this->parameters = $parameters;
233 $this->http_method = $http_method;
234 $this->http_url = $http_url;
235 }
236
237
238 /**
239 * attempt to build up a request from what was passed to the server
240 */
241 public static function from_request($http_method=NULL, $http_url=NULL, $parameters=NULL) {
242 $scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on")
243 ? 'http'
244 : 'https';
245 @$http_url or $http_url = $scheme .
246 '://' . $_SERVER['HTTP_HOST'] .
247 ':' .
248 $_SERVER['SERVER_PORT'] .
249 $_SERVER['REQUEST_URI'];
250 @$http_method or $http_method = $_SERVER['REQUEST_METHOD'];
251
252 // We weren't handed any parameters, so let's find the ones relevant to
253 // this request.
254 // If you run XML-RPC or similar you should use this to provide your own
255 // parsed parameter-list
256 if (!$parameters) {
257 // Find request headers
258 $request_headers = OAuthUtil::get_headers();
259
260 // Parse the query-string to find GET parameters
261 $parameters = OAuthUtil::parse_parameters($_SERVER['QUERY_STRING']);
262
263 // It's a POST request of the proper content-type, so parse POST
264 // parameters and add those overriding any duplicates from GET
265 if ($http_method == "POST"
266 && @strstr($request_headers["Content-Type"],
267 "application/x-www-form-urlencoded")
268 ) {
269 $post_data = OAuthUtil::parse_parameters(
270 file_get_contents(self::$POST_INPUT)
271 );
272 $parameters = array_merge($parameters, $post_data);
273 }
274
275 // We have a Authorization-header with OAuth data. Parse the header
276 // and add those overriding any duplicates from GET or POST
277 if (@substr($request_headers['Authorization'], 0, 6) == "OAuth ") {
278 $header_parameters = OAuthUtil::split_header(
279 $request_headers['Authorization']
280 );
281 $parameters = array_merge($parameters, $header_parameters);
282 }
283
284 }
285
286 return new OAuthRequest($http_method, $http_url, $parameters);
287 }
288
289 /**
290 * pretty much a helper function to set up the request
291 */
292 public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters=NULL) {
293 @$parameters or $parameters = array();
294 $defaults = array("oauth_version" => OAuthRequest::$version,
295 "oauth_nonce" => OAuthRequest::generate_nonce(),
296 "oauth_timestamp" => OAuthRequest::generate_timestamp(),
297 "oauth_consumer_key" => $consumer->key);
298 if ($token)
299 $defaults['oauth_token'] = $token->key;
300
301 $parameters = array_merge($defaults, $parameters);
302
303 return new OAuthRequest($http_method, $http_url, $parameters);
304 }
305
306 public function set_parameter($name, $value, $allow_duplicates = true) {
307 if ($allow_duplicates && isset($this->parameters[$name])) {
308 // We have already added parameter(s) with this name, so add to the list
309 if (is_scalar($this->parameters[$name])) {
310 // This is the first duplicate, so transform scalar (string)
311 // into an array so we can add the duplicates
312 $this->parameters[$name] = array($this->parameters[$name]);
313 }
314
315 $this->parameters[$name][] = $value;
316 } else {
317 $this->parameters[$name] = $value;
318 }
319 }
320
321 public function get_parameter($name) {
322 return isset($this->parameters[$name]) ? $this->parameters[$name] : null;
323 }
324
325 public function get_parameters() {
326 return $this->parameters;
327 }
328
329 public function unset_parameter($name) {
330 unset($this->parameters[$name]);
331 }
332
333 /**
334 * The request parameters, sorted and concatenated into a normalized string.
335 * @return string
336 */
337 public function get_signable_parameters() {
338 // Grab all parameters
339 $params = $this->parameters;
340
341 // Remove oauth_signature if present
342 // Ref: Spec: 9.1.1 ("The oauth_signature parameter MUST be excluded.")
343 if (isset($params['oauth_signature'])) {
344 unset($params['oauth_signature']);
345 }
346
347 return OAuthUtil::build_http_query($params);
348 }
349
350 /**
351 * Returns the base string of this request
352 *
353 * The base string defined as the method, the url
354 * and the parameters (normalized), each urlencoded
355 * and the concated with &.
356 */
357 public function get_signature_base_string() {
358 $parts = array(
359 $this->get_normalized_http_method(),
360 $this->get_normalized_http_url(),
361 $this->get_signable_parameters()
362 );
363
364 $parts = OAuthUtil::urlencode_rfc3986($parts);
365
366 return implode('&', $parts);
367 }
368
369 /**
370 * just uppercases the http method
371 */
372 public function get_normalized_http_method() {
373 return strtoupper($this->http_method);
374 }
375
376 /**
377 * parses the url and rebuilds it to be
378 * scheme://host/path
379 */
380 public function get_normalized_http_url() {
381 $parts = parse_url($this->http_url);
382
383 $port = @$parts['port'];
384 $scheme = $parts['scheme'];
385 $host = $parts['host'];
386 $path = @$parts['path'];
387
388 $port or $port = ($scheme == 'https') ? '443' : '80';
389
390 if (($scheme == 'https' && $port != '443')
391 || ($scheme == 'http' && $port != '80')) {
392 $host = "$host:$port";
393 }
394 return "$scheme://$host$path";
395 }
396
397 /**
398 * builds a url usable for a GET request
399 */
400 public function to_url() {
401 $post_data = $this->to_postdata();
402 $out = $this->get_normalized_http_url();
403 if ($post_data) {
404 $out .= '?'.$post_data;
405 }
406 return $out;
407 }
408
409 /**
410 * builds the data one would send in a POST request
411 */
412 public function to_postdata() {
413 return OAuthUtil::build_http_query($this->parameters);
414 }
415
416 /**
417 * builds the Authorization: header
418 */
419 public function to_header($realm=null) {
420 $first = true;
421 if($realm) {
422 $out = 'Authorization: OAuth realm="' . OAuthUtil::urlencode_rfc3986($realm) . '"';
423 $first = false;
424 } else
425 $out = 'Authorization: OAuth';
426
427 $total = array();
428 foreach ($this->parameters as $k => $v) {
429 if (substr($k, 0, 5) != "oauth") continue;
430 if (is_array($v)) {
431 throw new OAuthException('Arrays not supported in headers');
432 }
433 $out .= ($first) ? ' ' : ',';
434 $out .= OAuthUtil::urlencode_rfc3986($k) .
435 '="' .
436 OAuthUtil::urlencode_rfc3986($v) .
437 '"';
438 $first = false;
439 }
440 return $out;
441 }
442
443 public function __toString() {
444 return $this->to_url();
445 }
446
447
448 public function sign_request($signature_method, $consumer, $token) {
449 $this->set_parameter(
450 "oauth_signature_method",
451 $signature_method->get_name(),
452 false
453 );
454 $signature = $this->build_signature($signature_method, $consumer, $token);
455 $this->set_parameter("oauth_signature", $signature, false);
456 }
457
458 public function build_signature($signature_method, $consumer, $token) {
459 $signature = $signature_method->build_signature($this, $consumer, $token);
460 return $signature;
461 }
462
463 /**
464 * util function: current timestamp
465 */
466 private static function generate_timestamp() {
467 return time();
468 }
469
470 /**
471 * util function: current nonce
472 */
473 private static function generate_nonce() {
474 $mt = microtime();
475 $rand = mt_rand();
476
477 return md5($mt . $rand); // md5s look nicer than numbers
478 }
479 }
480
481 class OAuthServer {
482 protected $timestamp_threshold = 300; // in seconds, five minutes
483 protected $version = '1.0'; // hi blaine
484 protected $signature_methods = array();
485
486 protected $data_store;
487
488 function __construct($data_store) {
489 $this->data_store = $data_store;
490 }
491
492 public function add_signature_method($signature_method) {
493 $this->signature_methods[$signature_method->get_name()] =
494 $signature_method;
495 }
496
497 // high level functions
498
499 /**
500 * process a request_token request
501 * returns the request token on success
502 */
503 public function fetch_request_token(&$request) {
504 $this->get_version($request);
505
506 $consumer = $this->get_consumer($request);
507
508 // no token required for the initial token request
509 $token = NULL;
510
511 $this->check_signature($request, $consumer, $token);
512
513 // Rev A change
514 $callback = $request->get_parameter('oauth_callback');
515 $new_token = $this->data_store->new_request_token($consumer, $callback);
516
517 return $new_token;
518 }
519
520 /**
521 * process an access_token request
522 * returns the access token on success
523 */
524 public function fetch_access_token(&$request) {
525 $this->get_version($request);
526
527 $consumer = $this->get_consumer($request);
528
529 // requires authorized request token
530 $token = $this->get_token($request, $consumer, "request");
531
532 $this->check_signature($request, $consumer, $token);
533
534 // Rev A change
535 $verifier = $request->get_parameter('oauth_verifier');
536 $new_token = $this->data_store->new_access_token($token, $consumer, $verifier);
537
538 return $new_token;
539 }
540
541 /**
542 * verify an api call, checks all the parameters
543 */
544 public function verify_request(&$request) {
545 $this->get_version($request);
546 $consumer = $this->get_consumer($request);
547 $token = $this->get_token($request, $consumer, "access");
548 $this->check_signature($request, $consumer, $token);
549 return array($consumer, $token);
550 }
551
552 // Internals from here
553 /**
554 * version 1
555 */
556 private function get_version(&$request) {
557 $version = $request->get_parameter("oauth_version");
558 if (!$version) {
559 // Service Providers MUST assume the protocol version to be 1.0 if this parameter is not present.
560 // Chapter 7.0 ("Accessing Protected Ressources")
561 $version = '1.0';
562 }
563 if ($version !== $this->version) {
564 throw new OAuthException("OAuth version '$version' not supported");
565 }
566 return $version;
567 }
568
569 /**
570 * figure out the signature with some defaults
571 */
572 private function get_signature_method(&$request) {
573 $signature_method =
574 @$request->get_parameter("oauth_signature_method");
575
576 if (!$signature_method) {
577 // According to chapter 7 ("Accessing Protected Ressources") the signature-method
578 // parameter is required, and we can't just fallback to PLAINTEXT
579 throw new OAuthException('No signature method parameter. This parameter is required');
580 }
581
582 if (!in_array($signature_method,
583 array_keys($this->signature_methods))) {
584 throw new OAuthException(
585 "Signature method '$signature_method' not supported " .
586 "try one of the following: " .
587 implode(", ", array_keys($this->signature_methods))
588 );
589 }
590 return $this->signature_methods[$signature_method];
591 }
592
593 /**
594 * try to find the consumer for the provided request's consumer key
595 */
596 private function get_consumer(&$request) {
597 $consumer_key = @$request->get_parameter("oauth_consumer_key");
598 if (!$consumer_key) {
599 throw new OAuthException("Invalid consumer key");
600 }
601
602 $consumer = $this->data_store->lookup_consumer($consumer_key);
603 if (!$consumer) {
604 throw new OAuthException("Invalid consumer");
605 }
606
607 return $consumer;
608 }
609
610 /**
611 * try to find the token for the provided request's token key
612 */
613 private function get_token(&$request, $consumer, $token_type="access") {
614 $token_field = @$request->get_parameter('oauth_token');
615 $token = $this->data_store->lookup_token(
616 $consumer, $token_type, $token_field
617 );
618 if (!$token) {
619 throw new OAuthException("Invalid $token_type token: $token_field");
620 }
621 return $token;
622 }
623
624 /**
625 * all-in-one function to check the signature on a request
626 * should guess the signature method appropriately
627 */
628 private function check_signature(&$request, $consumer, $token) {
629 // this should probably be in a different method
630 $timestamp = @$request->get_parameter('oauth_timestamp');
631 $nonce = @$request->get_parameter('oauth_nonce');
632
633 $this->check_timestamp($timestamp);
634 $this->check_nonce($consumer, $token, $nonce, $timestamp);
635
636 $signature_method = $this->get_signature_method($request);
637
638 $signature = $request->get_parameter('oauth_signature');
639 $valid_sig = $signature_method->check_signature(
640 $request,
641 $consumer,
642 $token,
643 $signature
644 );
645
646 if (!$valid_sig) {
647 throw new OAuthException("Invalid signature");
648 }
649 }
650
651 /**
652 * check that the timestamp is new enough
653 */
654 private function check_timestamp($timestamp) {
655 if( ! $timestamp )
656 throw new OAuthException(
657 'Missing timestamp parameter. The parameter is required'
658 );
659
660 // verify that timestamp is recentish
661 $now = time();
662 if (abs($now - $timestamp) > $this->timestamp_threshold) {
663 throw new OAuthException(
664 "Expired timestamp, yours $timestamp, ours $now"
665 );
666 }
667 }
668
669 /**
670 * check that the nonce is not repeated
671 */
672 private function check_nonce($consumer, $token, $nonce, $timestamp) {
673 if( ! $nonce )
674 throw new OAuthException(
675 'Missing nonce parameter. The parameter is required'
676 );
677
678 // verify that the nonce is uniqueish
679 $found = $this->data_store->lookup_nonce(
680 $consumer,
681 $token,
682 $nonce,
683 $timestamp
684 );
685 if ($found) {
686 throw new OAuthException("Nonce already used: $nonce");
687 }
688 }
689
690 }
691
692 class OAuthDataStore {
693 function lookup_consumer($consumer_key) {
694 // implement me
695 }
696
697 function lookup_token($consumer, $token_type, $token) {
698 // implement me
699 }
700
701 function lookup_nonce($consumer, $token, $nonce, $timestamp) {
702 // implement me
703 }
704
705 function new_request_token($consumer, $callback = null) {
706 // return a new token attached to this consumer
707 }
708
709 function new_access_token($token, $consumer, $verifier = null) {
710 // return a new access token attached to this consumer
711 // for the user associated with this token if the request token
712 // is authorized
713 // should also invalidate the request token
714 }
715
716 }
717
718 class OAuthUtil {
719 public static function urlencode_rfc3986($input) {
720 if (is_array($input)) {
721 return array_map(array('OAuthUtil', 'urlencode_rfc3986'), $input);
722 } else if (is_scalar($input)) {
723 return str_replace(
724 '+',
725 ' ',
726 str_replace('%7E', '~', rawurlencode($input))
727 );
728 } else {
729 return '';
730 }
731 }
732
733
734 // This decode function isn't taking into consideration the above
735 // modifications to the encoding process. However, this method doesn't
736 // seem to be used anywhere so leaving it as is.
737 public static function urldecode_rfc3986($string) {
738 return urldecode($string);
739 }
740
741 // Utility function for turning the Authorization: header into
742 // parameters, has to do some unescaping
743 // Can filter out any non-oauth parameters if needed (default behaviour)
744 public static function split_header($header, $only_allow_oauth_parameters = true) {
745 $pattern = '/(([-_a-z]*)=("([^"]*)"|([^,]*)),?)/';
746 $offset = 0;
747 $params = array();
748 while (preg_match($pattern, $header, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) {
749 $match = $matches[0];
750 $header_name = $matches[2][0];
751 $header_content = (isset($matches[5])) ? $matches[5][0] : $matches[4][0];
752 if (preg_match('/^oauth_/', $header_name) || !$only_allow_oauth_parameters) {
753 $params[$header_name] = OAuthUtil::urldecode_rfc3986($header_content);
754 }
755 $offset = $match[1] + strlen($match[0]);
756 }
757
758 if (isset($params['realm'])) {
759 unset($params['realm']);
760 }
761
762 return $params;
763 }
764
765 // helper to try to sort out headers for people who aren't running apache
766 public static function get_headers() {
767 if (function_exists('apache_request_headers')) {
768 // we need this to get the actual Authorization: header
769 // because apache tends to tell us it doesn't exist
770 $headers = apache_request_headers();
771
772 // sanitize the output of apache_request_headers because
773 // we always want the keys to be Cased-Like-This and arh()
774 // returns the headers in the same case as they are in the
775 // request
776 $out = array();
777 foreach( $headers AS $key => $value ) {
778 $key = str_replace(
779 " ",
780 "-",
781 ucwords(strtolower(str_replace("-", " ", $key)))
782 );
783 $out[$key] = $value;
784 }
785 } else {
786 // otherwise we don't have apache and are just going to have to hope
787 // that $_SERVER actually contains what we need
788 $out = array();
789 if( isset($_SERVER['CONTENT_TYPE']) )
790 $out['Content-Type'] = $_SERVER['CONTENT_TYPE'];
791 if( isset($_ENV['CONTENT_TYPE']) )
792 $out['Content-Type'] = $_ENV['CONTENT_TYPE'];
793
794 foreach ($_SERVER as $key => $value) {
795 if (substr($key, 0, 5) == "HTTP_") {
796 // this is chaos, basically it is just there to capitalize the first
797 // letter of every word that is not an initial HTTP and strip HTTP
798 // code from przemek
799 $key = str_replace(
800 " ",
801 "-",
802 ucwords(strtolower(str_replace("_", " ", substr($key, 5))))
803 );
804 $out[$key] = $value;
805 }
806 }
807 }
808 return $out;
809 }
810
811 // This function takes a input like a=b&a=c&d=e and returns the parsed
812 // parameters like this
813 // array('a' => array('b','c'), 'd' => 'e')
814 public static function parse_parameters( $input ) {
815 if (!isset($input) || !$input) return array();
816
817 $pairs = explode('&', $input);
818
819 $parsed_parameters = array();
820 foreach ($pairs as $pair) {
821 $split = explode('=', $pair, 2);
822 $parameter = OAuthUtil::urldecode_rfc3986($split[0]);
823 $value = isset($split[1]) ? OAuthUtil::urldecode_rfc3986($split[1]) : '';
824
825 if (isset($parsed_parameters[$parameter])) {
826 // We have already recieved parameter(s) with this name, so add to the list
827 // of parameters with this name
828
829 if (is_scalar($parsed_parameters[$parameter])) {
830 // This is the first duplicate, so transform scalar (string) into an array
831 // so we can add the duplicates
832 $parsed_parameters[$parameter] = array($parsed_parameters[$parameter]);
833 }
834
835 $parsed_parameters[$parameter][] = $value;
836 } else {
837 $parsed_parameters[$parameter] = $value;
838 }
839 }
840 return $parsed_parameters;
841 }
842
843 public static function build_http_query($params) {
844 if (!$params) return '';
845
846 // Urlencode both keys and values
847 $keys = OAuthUtil::urlencode_rfc3986(array_keys($params));
848 $values = OAuthUtil::urlencode_rfc3986(array_values($params));
849 $params = array_combine($keys, $values);
850
851 // Parameters are sorted by name, using lexicographical byte value ordering.
852 // Ref: Spec: 9.1.1 (1)
853 uksort($params, 'strcmp');
854
855 $pairs = array();
856 foreach ($params as $parameter => $value) {
857 if (is_array($value)) {
858 // If two or more parameters share the same name, they are sorted by their value
859 // Ref: Spec: 9.1.1 (1)
860 natsort($value);
861 foreach ($value as $duplicate_value) {
862 $pairs[] = $parameter . '=' . $duplicate_value;
863 }
864 } else {
865 $pairs[] = $parameter . '=' . $value;
866 }
867 }
868 // For each parameter, the name is separated from the corresponding value by an '=' character (ASCII code 61)
869 // Each name-value pair is separated by an '&' character (ASCII code 38)
870 return implode('&', $pairs);
871 }
872 }
873
874 ?>
@@ -0,0 +1,245
1 <?php
2
3 /*
4 * Abraham Williams (abraham@abrah.am) http://abrah.am
5 *
6 * The first PHP Library to support OAuth for Twitter's REST API.
7 */
8
9 /* Load OAuth lib. You can find it at http://oauth.net */
10 require_once('OAuth.php');
11
12 /**
13 * Twitter OAuth class
14 */
15 class TwitterOAuth {
16 /* Contains the last HTTP status code returned. */
17 public $http_code;
18 /* Contains the last API call. */
19 public $url;
20 /* Set up the API root URL. */
21 public $host = "https://api.twitter.com/1/";
22 /* Set timeout default. */
23 public $timeout = 30;
24 /* Set connect timeout. */
25 public $connecttimeout = 30;
26 /* Verify SSL Cert. */
27 public $ssl_verifypeer = FALSE;
28 /* Respons format. */
29 public $format = 'json';
30 /* Decode returned json data. */
31 public $decode_json = TRUE;
32 /* Contains the last HTTP headers returned. */
33 public $http_info;
34 /* Set the useragnet. */
35 public $useragent = 'TwitterOAuth v0.2.0-beta2';
36 /* Immediately retry the API call if the response was not successful. */
37 //public $retry = TRUE;
38
39
40
41
42 /**
43 * Set API URLS
44 */
45 function accessTokenURL() { return 'https://api.twitter.com/oauth/access_token'; }
46 function authenticateURL() { return 'https://twitter.com/oauth/authenticate'; }
47 function authorizeURL() { return 'https://twitter.com/oauth/authorize'; }
48 function requestTokenURL() { return 'https://api.twitter.com/oauth/request_token'; }
49
50 /**
51 * Debug helpers
52 */
53 function lastStatusCode() { return $this->http_status; }
54 function lastAPICall() { return $this->last_api_call; }
55
56 /**
57 * construct TwitterOAuth object
58 */
59 function __construct($consumer_key, $consumer_secret, $oauth_token = NULL, $oauth_token_secret = NULL) {
60 $this->sha1_method = new OAuthSignatureMethod_HMAC_SHA1();
61 $this->consumer = new OAuthConsumer($consumer_key, $consumer_secret);
62 if (!empty($oauth_token) && !empty($oauth_token_secret)) {
63 $this->token = new OAuthConsumer($oauth_token, $oauth_token_secret);
64 } else {
65 $this->token = NULL;
66 }
67 }
68
69
70 /**
71 * Get a request_token from Twitter
72 *
73 * @returns a key/value array containing oauth_token and oauth_token_secret
74 */
75 function getRequestToken($oauth_callback = NULL) {
76 $parameters = array();
77 if (!empty($oauth_callback)) {
78 $parameters['oauth_callback'] = $oauth_callback;
79 }
80 $request = $this->oAuthRequest($this->requestTokenURL(), 'GET', $parameters);
81 $token = OAuthUtil::parse_parameters($request);
82 $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']);
83 return $token;
84 }
85
86 /**
87 * Get the authorize URL
88 *
89 * @returns a string
90 */
91 function getAuthorizeURL($token, $sign_in_with_twitter = TRUE) {
92 if (is_array($token)) {
93 $token = $token['oauth_token'];
94 }
95 if (empty($sign_in_with_twitter)) {
96 return $this->authorizeURL() . "?oauth_token={$token}";
97 } else {
98 return $this->authenticateURL() . "?oauth_token={$token}";
99 }
100 }
101
102 /**
103 * Exchange request token and secret for an access token and
104 * secret, to sign API calls.
105 *
106 * @returns array("oauth_token" => "the-access-token",
107 * "oauth_token_secret" => "the-access-secret",
108 * "user_id" => "9436992",
109 * "screen_name" => "abraham")
110 */
111 function getAccessToken($oauth_verifier = FALSE) {
112 $parameters = array();
113 if (!empty($oauth_verifier)) {
114 $parameters['oauth_verifier'] = $oauth_verifier;
115 }
116 $request = $this->oAuthRequest($this->accessTokenURL(), 'GET', $parameters);
117 $token = OAuthUtil::parse_parameters($request);
118 $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']);
119 return $token;
120 }
121
122 /**
123 * One time exchange of username and password for access token and secret.
124 *
125 * @returns array("oauth_token" => "the-access-token",
126 * "oauth_token_secret" => "the-access-secret",
127 * "user_id" => "9436992",
128 * "screen_name" => "abraham",
129 * "x_auth_expires" => "0")
130 */
131 function getXAuthToken($username, $password) {
132 $parameters = array();
133 $parameters['x_auth_username'] = $username;
134 $parameters['x_auth_password'] = $password;
135 $parameters['x_auth_mode'] = 'client_auth';
136 $request = $this->oAuthRequest($this->accessTokenURL(), 'POST', $parameters);
137 $token = OAuthUtil::parse_parameters($request);
138 $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']);
139 return $token;
140 }
141
142 /**
143 * GET wrapper for oAuthRequest.
144 */
145 function get($url, $parameters = array()) {
146 $response = $this->oAuthRequest($url, 'GET', $parameters);
147 if ($this->format === 'json' && $this->decode_json) {
148 return json_decode($response);
149 }
150 return $response;
151 }
152
153 /**
154 * POST wrapper for oAuthRequest.
155 */
156 function post($url, $parameters = array()) {
157 $response = $this->oAuthRequest($url, 'POST', $parameters);
158 if ($this->format === 'json' && $this->decode_json) {
159 return json_decode($response);
160 }
161 return $response;
162 }
163
164 /**
165 * DELETE wrapper for oAuthReqeust.
166 */
167 function delete($url, $parameters = array()) {
168 $response = $this->oAuthRequest($url, 'DELETE', $parameters);
169 if ($this->format === 'json' && $this->decode_json) {
170 return json_decode($response);
171 }
172 return $response;
173 }
174
175 /**
176 * Format and sign an OAuth / API request
177 */
178 function oAuthRequest($url, $method, $parameters) {
179 if (strrpos($url, 'https://') !== 0 && strrpos($url, 'http://') !== 0) {
180 $url = "{$this->host}{$url}.{$this->format}";
181 }
182 $request = OAuthRequest::from_consumer_and_token($this->consumer, $this->token, $method, $url, $parameters);
183 $request->sign_request($this->sha1_method, $this->consumer, $this->token);
184 switch ($method) {
185 case 'GET':
186 return $this->http($request->to_url(), 'GET');
187 default:
188 return $this->http($request->get_normalized_http_url(), $method, $request->to_postdata());
189 }
190 }
191
192 /**
193 * Make an HTTP request
194 *
195 * @return API results
196 */
197 function http($url, $method, $postfields = NULL) {
198 $this->http_info = array();
199 $ci = curl_init();
200 /* Curl settings */
201 curl_setopt($ci, CURLOPT_USERAGENT, $this->useragent);
202 curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, $this->connecttimeout);
203 curl_setopt($ci, CURLOPT_TIMEOUT, $this->timeout);
204 curl_setopt($ci, CURLOPT_RETURNTRANSFER, TRUE);
205 curl_setopt($ci, CURLOPT_HTTPHEADER, array('Expect:'));
206 curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, $this->ssl_verifypeer);
207 curl_setopt($ci, CURLOPT_HEADERFUNCTION, array($this, 'getHeader'));
208 curl_setopt($ci, CURLOPT_HEADER, FALSE);
209
210 switch ($method) {
211 case 'POST':
212 curl_setopt($ci, CURLOPT_POST, TRUE);
213 if (!empty($postfields)) {
214 curl_setopt($ci, CURLOPT_POSTFIELDS, $postfields);
215 }
216 break;
217 case 'DELETE':
218 curl_setopt($ci, CURLOPT_CUSTOMREQUEST, 'DELETE');
219 if (!empty($postfields)) {
220 $url = "{$url}?{$postfields}";
221 }
222 }
223
224 curl_setopt($ci, CURLOPT_URL, $url);
225 $response = curl_exec($ci);
226 $this->http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE);
227 $this->http_info = array_merge($this->http_info, curl_getinfo($ci));
228 $this->url = $url;
229 curl_close ($ci);
230 return $response;
231 }
232
233 /**
234 * Get the header info to store.
235 */
236 function getHeader($ch, $header) {
237 $i = strpos($header, ':');
238 if (!empty($i)) {
239 $key = str_replace('-', '_', strtolower(substr($header, 0, $i)));
240 $value = trim(substr($header, $i + 2));
241 $this->http_header[$key] = $value;
242 }
243 return strlen($header);
244 }
245 }
@@ -0,0 +1,246
1 <?php
2
3 /*
4 * Abraham Williams (abraham@abrah.am) http://abrah.am
5 *
6 * The first PHP Library to support OAuth for Twitter's REST API.
7 */
8
9 /* Load OAuth lib. You can find it at http://oauth.net */
10 require_once('OAuth.php');
11
12 /**
13 * Twitter OAuth class
14 */
15 class TwitterOAuth {
16 /* Contains the last HTTP status code returned. */
17 public $http_code;
18 /* Contains the last API call. */
19 public $url;
20 /* Set up the API root URL. */
21 public $host = "https://api.twitter.com/1/";
22 /* Set timeout default. */
23 public $timeout = 30;
24 /* Set connect timeout. */
25 public $connecttimeout = 30;
26 /* Verify SSL Cert. */
27 public $ssl_verifypeer = FALSE;
28 /* Respons format. */
29 public $format = 'json';
30 /* Decode returned json data. */
31 public $decode_json = TRUE;
32 /* Contains the last HTTP headers returned. */
33 public $http_info;
34 /* Set the useragnet. */
35 public $useragent = 'TwitterOAuth v0.2.0-beta2';
36 /* Immediately retry the API call if the response was not successful. */
37 //public $retry = TRUE;
38
39
40
41
42 /**
43 * Set API URLS
44 */
45 function accessTokenURL() { return 'https://api.twitter.com/oauth/access_token'; }
46 function authenticateURL() { return 'https://api.twitter.com/oauth/authenticate'; }
47 function authorizeURL() { return 'https://api.twitter.com/oauth/authorize'; }
48 function requestTokenURL() { return 'https://api.twitter.com/oauth/request_token'; }
49
50 /**
51 * Debug helpers
52 */
53 function lastStatusCode() { return $this->http_status; }
54 function lastAPICall() { return $this->last_api_call; }
55
56 /**
57 * construct TwitterOAuth object
58 */
59 function __construct($consumer_key, $consumer_secret, $oauth_token = NULL, $oauth_token_secret = NULL) {
60 $this->sha1_method = new OAuthSignatureMethod_HMAC_SHA1();
61 $this->consumer = new OAuthConsumer($consumer_key, $consumer_secret);
62 if (!empty($oauth_token) && !empty($oauth_token_secret)) {
63 $this->token = new OAuthConsumer($oauth_token, $oauth_token_secret);
64 } else {
65 $this->token = NULL;
66 }
67 }
68
69
70 /**
71 * Get a request_token from Twitter
72 *
73 * @returns a key/value array containing oauth_token and oauth_token_secret
74 */
75 function getRequestToken($oauth_callback = NULL) {
76 $parameters = array();
77 if (!empty($oauth_callback)) {
78 $parameters['oauth_callback'] = $oauth_callback;
79 }
80 $request = $this->oAuthRequest($this->requestTokenURL(), 'GET', $parameters);
81 $token = OAuthUtil::parse_parameters($request);
82 $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']);
83 return $token;
84 }
85
86 /**
87 * Get the authorize URL
88 *
89 * @returns a string
90 */
91 function getAuthorizeURL($token, $sign_in_with_twitter = TRUE) {
92 if (is_array($token)) {
93 $token = $token['oauth_token'];
94 }
95 if (empty($sign_in_with_twitter)) {
96 return $this->authorizeURL() . "?oauth_token={$token}";
97 } else {
98 return $this->authenticateURL() . "?oauth_token={$token}";
99 }
100 }
101
102 /**
103 * Exchange request token and secret for an access token and
104 * secret, to sign API calls.
105 *
106 * @returns array("oauth_token" => "the-access-token",
107 * "oauth_token_secret" => "the-access-secret",
108 * "user_id" => "9436992",
109 * "screen_name" => "abraham")
110 */
111 function getAccessToken($oauth_verifier = FALSE) {
112 $parameters = array();
113 if (!empty($oauth_verifier)) {
114 $parameters['oauth_verifier'] = $oauth_verifier;
115 }
116 $request = $this->oAuthRequest($this->accessTokenURL(), 'GET', $parameters);
117 $token = OAuthUtil::parse_parameters($request);
118 $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']);
119 return $token;
120 }
121
122 /**
123 * One time exchange of username and password for access token and secret.
124 *
125 * @returns array("oauth_token" => "the-access-token",
126 * "oauth_token_secret" => "the-access-secret",
127 * "user_id" => "9436992",
128 * "screen_name" => "abraham",
129 * "x_auth_expires" => "0")
130 */
131 function getXAuthToken($username, $password) {
132 $parameters = array();
133 $parameters['x_auth_username'] = $username;
134 $parameters['x_auth_password'] = $password;
135 $parameters['x_auth_mode'] = 'client_auth';
136 $request = $this->oAuthRequest($this->accessTokenURL(), 'POST', $parameters);
137 $token = OAuthUtil::parse_parameters($request);
138 $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']);
139 return $token;
140 }
141
142 /**
143 * GET wrapper for oAuthRequest.
144 */
145 function get($url, $parameters = array()) {
146 $response = $this->oAuthRequest($url, 'GET', $parameters);
147 if ($this->format === 'json' && $this->decode_json) {
148 return json_decode($response);
149 }
150 return $response;
151 }
152
153 /**
154 * POST wrapper for oAuthRequest.
155 */
156 function post($url, $parameters = array()) {
157 $response = $this->oAuthRequest($url, 'POST', $parameters);
158 if ($this->format === 'json' && $this->decode_json) {
159 return json_decode($response);
160 }
161 return $response;
162 }
163
164 /**
165 * DELETE wrapper for oAuthReqeust.
166 */
167 function delete($url, $parameters = array()) {
168 $response = $this->oAuthRequest($url, 'DELETE', $parameters);
169 if ($this->format === 'json' && $this->decode_json) {
170 return json_decode($response);
171 }
172 return $response;
173 }
174
175 /**
176 * Format and sign an OAuth / API request
177 */
178 function oAuthRequest($url, $method, $parameters) {
179 if (strrpos($url, 'https://') !== 0 && strrpos($url, 'http://') !== 0) {
180 $url = "{$this->host}{$url}.{$this->format}";
181 }
182 $request = OAuthRequest::from_consumer_and_token($this->consumer, $this->token, $method, $url, $parameters);
183 $request->sign_request($this->sha1_method, $this->consumer, $this->token);
184 switch ($method) {
185 case 'GET':
186 return $this->http($request->to_url(), 'GET');
187 default:
188 return $this->http($request->get_normalized_http_url(), $method, $request->to_postdata());
189 }
190 }
191
192 /**
193 * Make an HTTP request
194 *
195 * @return API results
196 */
197 function http($url, $method, $postfields = NULL) {
198 $this->http_info = array();
199 $ci = curl_init();
200 /* Curl settings */
201 curl_setopt($ci, CURLOPT_USERAGENT, $this->useragent);
202 curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, $this->connecttimeout);
203 curl_setopt($ci, CURLOPT_TIMEOUT, $this->timeout);
204 curl_setopt($ci, CURLOPT_RETURNTRANSFER, TRUE);
205 curl_setopt($ci, CURLOPT_HTTPHEADER, array('Expect:'));
206 curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, $this->ssl_verifypeer);
207 curl_setopt($ci, CURLOPT_HEADERFUNCTION, array($this, 'getHeader'));
208 curl_setopt($ci, CURLOPT_HEADER, FALSE);
209
210 switch ($method) {
211 case 'POST':
212 curl_setopt($ci, CURLOPT_POST, TRUE);
213 if (!empty($postfields)) {
214 curl_setopt($ci, CURLOPT_POSTFIELDS, $postfields);
215 }
216 break;
217 case 'DELETE':
218 curl_setopt($ci, CURLOPT_CUSTOMREQUEST, 'DELETE');
219 if (!empty($postfields)) {
220 $url = "{$url}?{$postfields}";
221 }
222 }
223
224 curl_setopt($ci, CURLOPT_URL, $url);
225 $response = curl_exec($ci);
226 $this->http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE);
227 $this->http_info = array_merge($this->http_info, curl_getinfo($ci));
228 $this->url = $url;
229 curl_close ($ci);
230 return $response;
231 }
232
233 /**
234 * Get the header info to store.
235 */
236 function getHeader($ch, $header) {
237 $i = strpos($header, ':');
238 if (!empty($i)) {
239 $key = str_replace('-', '_', strtolower(substr($header, 0, $i)));
240 $value = trim(substr($header, $i + 2));
241 $this->http_header[$key] = $value;
242 }
243 return strlen($header);
244 }
245 }
246
@@ -0,0 +1,27
1 <?php
2
3 /* Types */
4
5 function get_typeByID( $id ) {
6 global $mtdb;
7 $id = (int)$id;
8 $r = $mtdb->getRow( 'SELECT id, name, description FROM strip_t WHERE id=' . $id );
9 $r->meta = $mtdb->getAll( 'SELECT meta as id from meta where type=' . $id);
10 return $r;
11 }
12
13 function get_allTypes() {
14 global $mtdb;
15 return $mtdb->getRow( 'SELECT id, name, description, meta FROM strip_t' );
16 }
17
18 function get_allMetaTypes() {
19 global $mtdb;
20 return $mtdb->getAll("SELECT id, name FROM meta_t");
21 }
22
23 function _getMetaNameFromObject($obj) {
24 return $obj->name;
25 }
26
27 ?> No newline at end of file
@@ -0,0 +1,105
1 <?php
2
3 // Do we have a rant image being uploaded?
4 function is_valid_upload( $field = 'ranterImage', $index = null ) {
5 global $_FILES;
6 if( !$_FILES[$field] ) return false;
7 # echo "Passed test 1<br>";
8
9 if(is_null($index)) {
10 if( '' == $_FILES[$field]['tmp_name'] ) return false;
11 # echo "Passed single test 2<br>";
12 if( UPLOAD_ERR_NO_FILE == $_FILES[$field]['error'] ) return false;
13 # echo "Passed single test 3<br>";
14 if( 0 == $_FILES[$field]['size'] ) return false;
15 # echo "Passed single test 4<br>";
16 } else {
17 if( !is_array($_FILES[$field]['tmp_name']) ) return false;
18 # echo "Passed array text 2<br>";
19 if( '' == $_FILES[$field]['tmp_name'][$index] ) return false;
20 # echo "Passed array test 3<br>";
21 if( UPLOAD_ERR_NO_FILE == $_FILES[$field]['error'][$index] ) return false;
22 # echo "Passed array test 4<br>";
23 if( 0 == $_FILES[$field]['size'][$index] ) return false;
24 # echo "Passed array test 5<br>";
25 }
26
27 return true;
28 }
29
30
31 function pre_upload_rant_image( $pathtofile ) {
32 if( !is_valid_upload() ) return array();
33 $image_data = getimagesize( $pathtofile );
34 $doing_upload = false;
35 $upload_imagetype = null;
36 $upload_error = false;
37
38 if( false === $image_data ) {
39 $upload_error='<p>Something wronky happened with that upload, getimagesize() returned false!</p>';
40 } elseif( 300 > $image_data[0] ) {
41 $upload_error='<p>Image too narrow, only '.$image_data[0].'px tall. Rant saved as draft. Try uploading image again.</p>';
42 } elseif ( 245 > $image_data[1] ) {
43 $upload_error='<p>Image too short, only '.$image_data[1].'px tall. Rant saved as draft. Try uploading image again.</p>';
44 } elseif( false === $image_data[2] ) {
45 $upload_error='<p>Unknown image type or extension. Upload refused. Rant saved as draft. Try uploading image again.</p>';
46 } elseif( !is_uploaded_file( $pathtofile ) ) {
47 $upload_error="<p>Something bad happened, that's not a valid file upload! Rant saved as draft. Try uploading image again.</p>";
48 } else {
49 // Valid upload. It will be moved into place later.
50 $upload_imagetype = $image_data[2];
51 $doing_upload = true;
52 }
53 return compact( "upload_error", "doing_upload", "upload_imagetype" );
54 }
55
56 function save_stock_rant_image( $source, $rant ) {
57 if( copy( sprintf( '%s/%s/%s', SITE_PATH_ABS,SITE_RANT,$source),
58 SITE_PATH_ABS .'/'.get_rantimage_filename($rant) ) ) {
59 $upload_info='<p>Default rant image copied.</p>';
60 } else {
61 $upload_error='<p>There was an error copying the default rant image into place.</p>';
62 }
63 return compact("upload_info","upload_error");
64 }
65
66 function save_upload_rant_image( $source, $rant ) {
67 $destination = SITE_PATH_ABS.'/'.get_rantimage_filename($rant);
68 $size = getimagesize($source);
69
70 if(300 == $size[0] && 245 == $size[1]) {
71 if( move_uploaded_file($source, $destination) ) {
72 $upload_info='<p>New rant image uploaded for rant '. $rant->id .'.</p>';
73 } else {
74 $upload_error='<p>Something went wrong while moving the uploaded image.</p>';
75 }
76 } else {
77 if( crop_resize($source, $destination) ) {
78 $upload_info='<p>New rant image uploaded and resized for rant '. $rant->id .'.</p>';
79 } else {
80 $upload_error='<p>Something went wrong while transforming the uploaded image.</p>';
81 }
82 }
83
84 return compact("upload_info","upload_error");
85 }
86
87 function save_upload_rant_attachment( $source, $rant )
88 {
89 global $mtdb;
90
91 $image_data = getimagesize( $source );
92 $mtdb->query( "INSERT INTO rant_attachment (rant, media) VALUES ($rant, $image_data[2])" );
93 $rant_attachment_id = mysql_insert_id( $mtdb->link );
94
95 if( move_uploaded_file($source, SITE_PATH_ABS.'/'.get_rantattachment_filename($rant_attachment_id) ) ) {
96 $upload_info='<p>New rant attachment uploaded for rant '. $rant .'.</p>';
97 adminlog('Rant attachment uploaded', MTS_RANT, MTA_ADD);
98 } else {
99 $upload_error='<p>Something went wrong while storing the attachment.</p>';
100 }
101
102 return compact("rant_attachment_id","upload_info","upload_error");
103 }
104
105 ?>
@@ -0,0 +1,35
1 <?php
2
3 $currentuser=false;
4
5 function getCurrentUser() {
6 global $currentuser;
7 echo $currentuser->name;
8 }
9
10 function get_userdatabyid( $id ) {
11 global $mtdb;
12 return $mtdb->getRow( 'SELECT id,name,email,nameplate,default_image,default_link FROM contributor WHERE id = ' . (int)$id );
13 }
14
15 function get_userdatabylogin( $username ) {
16 global $mtdb;
17 return $mtdb->getRow( 'SELECT id,name,email,nameplate,default_image,default_link FROM contributor WHERE name = "' . mysql_real_escape_string($username) . '"' );
18 }
19
20 function save_userdata( $user ) {
21 adminlog("Saved changes to user ".$user->id." (".$user->name.").", MTS_USER, MTA_UPDATE);
22 global $mtdb;
23 return $mtdb->query( sprintf( 'UPDATE contributor SET email="%s", nameplate="%s", default_image="%s", default_link="%s" WHERE id=%d',
24 mysql_real_escape_string($user->email), mysql_real_escape_string($user->nameplate),
25 mysql_real_escape_string($user->default_image), mysql_real_escape_string($user->default_link), $user->id) );
26 }
27
28 function change_password( $user ) {
29 adminlog("Changed password for user ".$user->id." (".$user->name.").", MTS_USER, MTA_UPDATE);
30 global $mtdb, $currentuser;
31 if( $currentuser->id === $user->id ) mt_setcookie($user->name, $user->password, false, ADMINURL, FALSE );
32 return $mtdb->query( 'UPDATE contributor SET password=SHA1( "' . mysql_real_escape_string($user->password) . '" ) WHERE id = "' . mysql_real_escape_string($user->id) . '"' );
33 }
34
35 ?>
@@ -0,0 +1,109
1 <?php
2
3 require_once('include/admin.inc.php');
4
5 auth_redirect(); // Require logged in user to access this page.
6
7 function human_time_diff( $from, $to = '' ) {
8 if ( empty($to) )
9 $to = time();
10 $diff = (int) abs($to - $from);
11 if ($diff <= 3600) {
12 $mins = round($diff / 60);
13 if ($mins <= 1) {
14 $mins = 1;
15 }
16 $since = sprintf( $mins == 1 ? '%s minute' : '%s minutes', $mins);
17 } elseif ($diff <= 86400) {
18 $hours = round($diff / 3600);
19 if ($hours <= 1) {
20 $hour = 1;
21 }
22 $since = sprintf( $hours == 1 ? '%s hour' : '%s hours', $hours);
23 } elseif($diff <= 604800 ) {
24 $days = round($diff / 86400);
25 if ($days <= 1) {
26 $days = 1;
27 }
28 $since = sprintf( $days == 1 ? '%s day' : '%s days', $days);
29 } else {
30 $weeks = round($diff / 604800);
31 if( $weeks <= 1) {
32 $weeks = 1;
33 }
34 $since = sprintf( $weeks == 1 ? '%s week' : '%s weeks', $weeks);
35 }
36
37 return $since;
38 }
39
40
41 adminhead();
42 adminmenu();
43 ?>
44 <h2>Scratchpad</h2>
45 <form method="post" action="post-scratchpad.php">
46 <?php nonce_field('new-scratchpad'); ?>
47 <ul class="historic">
48 <?php
49 $strips = array_reverse( $mtdb->getAll('SELECT UNIX_TIMESTAMP(s.published) AS pubdate, c.name, s.message FROM scratchpad s JOIN contributor c ON s.contributor = c.id ORDER BY published DESC LIMIT 5') );
50
51 foreach($strips as $k=>$v)
52 {
53 $message = preg_replace('/(https?\:\/\/[^"\s\<\>]*[^.,;\'">\:\s\<\>\)\]\!])/i',
54 '<a href="$1">$1</a>', htmlentities($v->message));
55 printf( '<li>%s wrote %s ago: %s</li>', htmlspecialchars($v->name), human_time_diff($v->pubdate), $message);
56 }
57 ?>
58 </ul>
59 <p style="padding-bottom:1em;"><input type="text" name="message" /><input type="submit" value="Send" /></p>
60
61 </form><br>
62
63 <h2>Recent Strips</h2>
64 <ul class="historic">
65 <?php
66 $strips = $mtdb->getAll("SELECT distinct id, title, UNIX_TIMESTAMP(published) as date FROM strip WHERE published <= NOW() order by id DESC LIMIT 5");
67
68 foreach($strips as $k=>$v) {
69 printf( '<li>%d: <a href="%s/index.php?strip_id=%d">%s</a>, %s ago</li>', $v->id, SITE_HOST . SITE_PATH, $v->id, htmlspecialchars($v->title), human_time_diff($v->date) );
70 }
71 ?>
72 </ul><br>
73
74 <h2>Upcoming Strips</h2>
75 <ul class="historic">
76 <?php
77 $strips = $mtdb->getAll("SELECT distinct id, title, UNIX_TIMESTAMP(published) as date FROM strip WHERE published > NOW() order by id ASC LIMIT 5");
78
79 foreach($strips as $k=>$v) {
80 printf( '<li>%d: <a href="%s/edit-comic.php?strip_id=%d">%s</a>, in %s</li>', $v->id, SITE_HOST . SITE_PATH . '/' . SITE_ADMIN, $v->id, htmlspecialchars($v->title), human_time_diff($v->date) );
81 }
82 ?>
83 </ul><br>
84
85 <h2>Recent Published Rants</h2>
86 <ul class="historic">
87 <?php
88 $rants = $mtdb->getAll('SELECT distinct rant.id,UNIX_TIMESTAMP(rant.published) as date,rant.title,contributor.name from rant,contributor where rant.author=contributor.id AND rant.status=\'published\' ORDER BY rant.published DESC limit 5');
89
90 foreach($rants as $k=>$v) {
91 printf( '<li>%d: <a href="%s/index.php?rant_id=%d">%s</a> by %s, %s ago</li>', $v->id, SITE_HOST . SITE_PATH, $v->id, htmlspecialchars($v->title), htmlspecialchars($v->name), human_time_diff($v->date) );
92 }
93 ?>
94 </ul><br>
95
96 <h2>Recent Draft Rants</h2>
97 <ul class="historic">
98 <?php
99 $rants = $mtdb->getAll('SELECT distinct rant.id,UNIX_TIMESTAMP(rant.published) as date,rant.title,contributor.name from rant,contributor where rant.author=contributor.id AND rant.status=\'draft\' ORDER BY rant.published DESC limit 5');
100
101 foreach($rants as $k=>$v) {
102 printf( '<li>%d: <a href="%s/edit-rant.php?rant_id=%d">%s</a> by %s, %s ago</li>', $v->id, SITE_HOST . ADMIN_PATH, $v->id, htmlspecialchars($v->title), htmlspecialchars($v->name), human_time_diff($v->date) );
103 }
104 ?>
105 </ul>
106
107 <?php
108 adminfooter();
109 ?>
@@ -0,0 +1,97
1 <?php
2
3 require_once('include/admin.inc.php');
4
5 /* Megatokyo admin system assumes that everyone has equivilent
6 ability to create and alter content. There are no permission
7 levels or access controls other than "Can they login?" */
8
9 $error = '';
10 switch( $_REQUEST['action'] ) {
11
12 case 'logout':
13 mt_clearcookie();
14 _redirect( ADMIN_PATH .'/login.php?loggedout=true' );
15
16 case 'login':
17 $log = $_POST['log'];
18 $pwd = $_POST['pwd'];
19
20 if( mt_login( $log, $pwd )) {
21 //logthis ( "AUTH: Successful login from $log at " . $_SERVER["REMOTE_ADDR"], false );
22 adminlog("User ".$log." has logged in from ".$_SERVER['REMOTE_ADDR'], MTS_LOGIN, MTA_CHANGE);
23 // correct password
24 // set cookie
25 mt_setcookie($log, $pwd, false, ADMIN_PATH, isset($_POST['rememberme']) );
26 if($_POST['redirect_to']) _redirect( $_POST['redirect_to'] );
27 _redirect( ADMIN_PATH .'/' );
28 } else {
29 //logthis ('AUTH: Failed login attempt from ' . $_SERVER["REMOTE_ADDR"], var_export( $_REQUEST, true ) );
30 }
31 // incorrect username or password, fall through to error display
32
33 case 'error':
34 default:
35
36 if ( !empty($_COOKIE[USER_COOKIE]) && mt_login($_COOKIE[USER_COOKIE], $_COOKIE[PASS_COOKIE], true) ) {
37 // Already logged in, redirect to admin dashboard.
38 nocache_headers();
39 _redirect( ADMIN_PATH .'/' );
40 }
41
42 if( $_GET['loggedout'] == true ) $error.='<p>Successfully logged you out.</p>';
43 ?>
44 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
45 <html xmlns="http://www.w3.org/1999/xhtml" lang="en-US" xml:lang="en-US">
46 <head>
47 <title>Megatokyo Admin &rsaquo; Login</title>
48 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
49 <meta name="generator" content="Alan J Castonguay, Robert Sherby, Jeremy Wagner-Kaiser, Shawn Morford (!! nathanbp, jrl !!)" />
50 <link rel="stylesheet" href="wp-admin.css" type="text/css" />
51 <!--[if IE]><style type="text/css">#login h1 a { margin-top: 35px; } #login ul { padding-bottom: 65px; }</style><![endif]--><!-- Curse you, IE! -->
52 <script type="text/javascript">
53 function focusit() {
54 document.getElementById('user_login').focus();
55 }
56 window.onload = focusit;
57 </script>
58 </head>
59 <body class="login">
60
61 <div id="login"><h1><a href="<?php echo SITE_HOST.SITE_PATH; ?>">Megatokyo Admin</a></h1>
62 <?php
63 if ( $error ) echo "<div id=\"login_error\">$error</div>\n";
64 ?>
65 <form name="loginform" id="loginform" action="login.php" method="post">
66 <?php if($_GET['redirect_to']) {
67 echo '<input type="hidden" name="redirect_to" value="' . htmlentities($_GET['redirect_to']) . '" />';
68 } ?>
69 <p>
70 <label>Username:<br/>
71 <input type="text" name="log" id="user_login" class="input" value="" size="20" tabindex="10" /></label>
72 </p>
73 <p>
74 <label>Password:<br/>
75 <input type="password" name="pwd" id="user_pass" class="input" value="" size="20" tabindex="20" /></label>
76 </p>
77 <hr/>
78 <p><label><input name="rememberme" type="checkbox" id="rememberme" value="forever" tabindex="90" /> Remember me</label></p>
79 <p class="submit">
80 <input type="submit" name="submit" id="submit" value="Login &raquo;" tabindex="100" />
81 <input type="hidden" name="action" value="login" />
82 </p>
83 </form></div>
84
85 <ul>
86 <li><a href="<?php echo SITE_HOST.SITE_PATH; ?>" title="Return to the public Megatokyo website.">Back to Megatokyo Website</a></li>
87 </ul>
88
89 </body>
90 </html>
91 <?php
92 die();
93
94 } // end switch
95
96
97 ?>
@@ -0,0 +1,74
1 <?php
2
3 /* This page displays a list of comics, 15 per page. */
4
5 require_once('include/admin.inc.php');
6
7 auth_redirect(); // Require logged in user to access this page.
8
9 adminhead('Manage Comics');
10 adminmenu();
11 ?>
12 <h2>Edit Comic</h2>
13
14 <?php
15
16 $page = 1;
17 if( isset($_GET['page'] )) $page = (int) $_GET['page'];
18
19 $perpage = 15;
20 $start = ($page-1) * $perpage;
21
22 $total = ceil( $mtdb->getOne("SELECT count(DISTINCT id) FROM strip") / $perpage );
23 $strips = $mtdb->getAll("SELECT id, UNIX_TIMESTAMP(published) as published, type, media, title, book, page FROM strip GROUP BY id ORDER BY id DESC LIMIT $start,$perpage");
24 $types_db = $mtdb->getAll("SELECT id,description FROM strip_t");
25
26 $type = array();
27 foreach( $types_db as $k ) $type[$k->id]=$k->description;
28
29
30 pagination( $page, $total );
31
32 ?>
33
34 <table class="widefat">
35 <thead>
36 <tr>
37 <th scope="col" style="text-align: center;">Strip #</th>
38 <th scope="col">Title</th>
39 <th scope="col">Published On</th>
40 <th scope="col">Type</th>
41 <th scope="col">Book Page #</th>
42 <th scope="col"></th>
43 <th scope="col"></th>
44 <th scope="col"></th>
45 </tr>
46 </thead>
47
48 <tbody id="the-list">
49 <?php
50 $alternate=false;
51 foreach( $strips as $s ) {
52 $alternate=!$alternate;
53 ?>
54 <tr id="comic-<?php echo $s->id; ?>" <?php if($alternate) echo 'class="alternate"'; ?>>
55 <th scope="row" style="text-align: center;"><?php echo $s->id; ?></th>
56 <td><?php echo $s->title; ?></td>
57 <td><?php echo htmlentities( date( 'Y-m-d H:i:s', $s->published)); ?></td>
58 <td><?php echo $type[$s->type]; ?></td>
59 <td><?php echo $s->book; ?> - <?php echo $s->page; ?></td>
60 <td style="text-align: center;"><a href="<?php echo SITE_HOST . SITE_PATH; ?>/strip/<?php echo $s->id; ?>">View</a></td>
61 <td style="text-align: center;"><a href="edit-comic.php?strip_id=<?php echo $s->id; ?>">Edit</a></td>
62 <td style="text-align: center;"><a class="delete" href="delete-comic.php?strip_id=<?php echo $s->id; ?>">Delete</a></td>
63 </tr>
64 <?php
65 }
66 ?>
67 </tbody>
68 </table>
69
70
71
72 <?php
73 adminfooter();
74 ?>
@@ -0,0 +1,106
1 <?php
2
3 require_once('include/admin.inc.php');
4
5 auth_redirect(); // Require logged in user to access this page.
6
7 if( isset($_GET['delete']) && (int)$_GET['delete'] ) {
8 check_nonce('delete-metatype-'.(int)$_GET['delete']);
9 if(! $mtdb->query( 'DELETE FROM meta_t WHERE id=' . (int)$_GET['delete'] ) )
10 {
11 adminlog("Error on deleting metatype ".(int)$_GET['delete'], MTS_TYPE_META, MTA_DELETE, E_WARNING);
12 mtdie("Error on update: ". htmlentities(mysql_error()));
13 }
14 $info.='<p>Deleted metatype successfully.<p>';
15 adminlog("Metatype ".(int)$_GET['delete']." deleted.", MTS_TYPE_META, MTA_DELETE);
16 }
17
18 if( isset($_POST['action']) && $_POST['action'] == 'new_meta' ) {
19 check_nonce('new-metatype');
20
21 $name = trim($_POST['name']);
22
23 if( check_type_name( $name ) ) {
24 if(! $mtdb->query( 'INSERT INTO meta_t(name) VALUES("'. mysql_real_escape_string($name) . '")' ) )
25 {
26 adminlog("Error on inserting metatype ".(int)$_GET['delete'], MTS_TYPE_META, MTA_INSERT, E_WARNING);
27 mtdie("Error on insertion: ". htmlentities(mysql_error()));
28 }
29 }
30 $info.='<p>New metatype created successfully.<p>';
31 adminlog("Metatype ".$name." added.", MTS_TYPE_META, MTA_ADD);
32 }
33
34 if( isset($_POST['action']) && $_POST['action'] == 'edit_meta' ) {
35 check_nonce('save-metatype-'.(int)$_POST['type_id']);
36
37 $name = trim($_POST['name']);
38
39 if( check_type_name( $name ) ) {
40 if(! $mtdb->query( 'UPDATE meta_t SET name = "' . mysql_real_escape_string($name) . '" WHERE id=' . (int)$_POST['type_id']) )
41 {
42 adminlog("Error updating metatype ".(int)$_GET['delete'], MTS_TYPE_META, MTA_UPDATE, E_WARNING);
43 mtdie("Error on update: ". htmlentities(mysql_error()));
44 }
45 }
46 $info.='<p>Changes to metatype saved successfully.<p>';
47 adminlog("Metatype ".$name." updated.", MTS_TYPE_META, MTA_UPDATE);
48 }
49
50 //get all metatypes
51 $metas = $mtdb->getAll("SELECT id, name FROM meta_t");
52
53 adminhead('Metatypes');
54 adminmenu();
55 ?>
56 <h2>Metatype Management</h2>
57 <p>Make changes to the metatypes which organize the types.</p>
58
59 <table class="widefat">
60 <thead>
61 <tr>
62 <th scope="col" style="text-align: center;">Metatype #</th>
63 <th scope="col">Name</th>
64 <th scope="col"></th>
65 <th scope="col"></th>
66 </tr>
67 </thead>
68
69 <tbody id="the-list">
70 <?php
71 $alternate=false;
72 foreach( $metas as $s ) {
73 $alternate=!$alternate;
74 ?>
75 <tr id="type-<?php echo $s->id; ?>" <?php if($alternate) echo 'class="alternate"'; ?>>
76 <th scope="row" style="text-align: center;"><?php echo $s->id; ?></th>
77 <td><?php echo htmlentities($s->name); ?></td>
78 <td style="text-align: center;"><a href="edit-metatype.php?edit=<?php echo (int)$s->id; ?>">Edit</a></td>
79 <td style="text-align: center;"><a class="delete" href="?delete=<?php echo (int)$s->id; ?>">Delete</a></td>
80 </tr>
81 <?php
82 }
83 ?>
84 </tbody>
85 </table>
86
87 <form enctype="multipart/form-data" name="create-user" id="create-user" action="manage-metatypes.php" method="post">
88 <?php nonce_field('new-metatype'); ?>
89 <input type="hidden" name="action" value="new_meta" />
90
91 <h2>Create New Metatype</h2>
92 <div class="narrow">
93 <table class="editform" width="100%" cellspacing="2" cellpadding="5">
94 <tr>
95 <th scope="row" width="33%">Name</th>
96 <td width="66%"><input name="name" type="text" id="name" value="" /></td>
97 </tr>
98 </table>
99
100 <p class="submit"><input type="submit" value="Create &raquo;" name="submit" /></p>
101 </div>
102 </form>
103
104 <?php
105 adminfooter();
106 ?> No newline at end of file
@@ -0,0 +1,67
1 <?php
2
3 /* This page displays a list of comics, 15 per page. */
4
5 require_once('include/admin.inc.php');
6
7 auth_redirect(); // Require logged in user to access this page.
8
9 adminhead('Manage Pages');
10 adminmenu();
11 ?>
12 <h2>Manage Pages</h2>
13
14 <?php
15
16 $page = 1;
17 if( isset($_GET['page'] )) $page = (int) $_GET['page'];
18
19 $perpage = 15;
20 $start = ($page-1) * $perpage;
21
22 $total = ceil( $mtdb->getOne("SELECT count(DISTINCT url_name) FROM static_page") / $perpage );
23 $pages = $mtdb->getAll("SELECT url_name, pubdate, status, title, body FROM static_page ORDER BY url_name ASC LIMIT $start,$perpage");
24
25 pagination( $page, $total );
26
27 ?>
28
29 <table class="widefat">
30 <thead>
31 <tr>
32 <th scope="col" style="text-align: center;">Page&nbsp;Name</th>
33 <th scope="col">Title</th>
34 <th scope="col">Status</th>
35 <th scope="col">Published&nbsp;On</th>
36 <th scope="col">Excerpt</th>
37 <th scope="col"></th>
38 <th scope="col"></th>
39 <th scope="col"></th>
40 </tr>
41 </thead>
42
43 <tbody id="the-list">
44 <?php
45 $alternate=false;
46 foreach( $pages as $p ) {
47 $alternate=!$alternate;
48 ?>
49 <tr id="page-<?php echo $p->url_name; ?>" <?php if($alternate) echo 'class="alternate"'; ?>>
50 <th scope="row" style="text-align: center;"><?php echo $p->url_name ?></th>
51 <td><?php echo $p->title; ?></td>
52 <td><?php echo $p->status; ?></td>
53 <td><?php echo $p->pubdate; ?></td>
54 <td><?php echo Excerpt($p->body,185); ?></td>
55 <td><?php echo '<a href="' . SITE_HOST.SITE_PATH.'/' . $p->url_name . '">View</a>'; ?></td>
56 <td style="text-align: center;"><a href="edit-page.php?page_name=<?php echo $p->url_name; ?>">Edit</a></td>
57 <td style="text-align: center;"><a class="delete" href="delete-page.php?page_name=<?php echo $p->url_name; ?>">Delete</a></td>
58 </tr>
59 <?php
60 }
61 ?>
62 </tbody>
63 </table>
64
65 <?php
66 adminfooter();
67 ?>
@@ -0,0 +1,69
1 <?php
2
3 /* This page displays a list of comics, 15 per page. */
4
5 require_once('include/admin.inc.php');
6
7 auth_redirect(); // Require logged in user to access this page.
8
9 adminhead('Manage Rants');
10 adminmenu();
11 ?>
12 <h2>Manage Rants</h2>
13
14 <?php
15
16 $page = 1;
17 if( isset($_GET['page'] )) $page = (int) $_GET['page'];
18
19 $perpage = 15;
20 $start = ($page-1) * $perpage;
21
22 $total = ceil( $mtdb->getOne("SELECT count(DISTINCT id) FROM rant") / $perpage );
23 $rants = $mtdb->getAll("SELECT r.id,UNIX_TIMESTAMP(r.published) AS published,c.name,r.title,r.body, r.status FROM rant r,contributor c WHERE c.id=r.author GROUP BY id ORDER BY id DESC LIMIT $start,$perpage");
24
25 pagination( $page, $total );
26
27 ?>
28
29 <table class="widefat">
30 <thead>
31 <tr>
32 <th scope="col" style="text-align: center;">Rant&nbsp;#</th>
33 <th scope="col">Author</th>
34 <th scope="col">Title</th>
35 <th scope="col">Status</th>
36 <th scope="col">Published&nbsp;On</th>
37 <th scope="col">Excerpt</th>
38 <th scope="col"></th>
39 <th scope="col"></th>
40 <th scope="col"></th>
41 </tr>
42 </thead>
43
44 <tbody id="the-list">
45 <?php
46 $alternate=false;
47 foreach( $rants as $r ) {
48 $alternate=!$alternate;
49 ?>
50 <tr id="rant-<?php echo $r->id; ?>" <?php if($alternate) echo 'class="alternate"'; ?>>
51 <th scope="row" style="text-align: center;"><?php echo $r->id; ?></th>
52 <td><?php echo $r->name; ?></td>
53 <td><?php echo $r->title; ?></td>
54 <td><?php echo $r->status; ?></td>
55 <td><?php echo htmlentities( date( 'Y-m-d H:i:s', $r->published)); ?></td>
56 <td><?php echo Excerpt($r->body,185); ?></td>
57 <td><?php echo '<a href="' . SITE_HOST.SITE_PATH.'/rant/' . $r->id . '">View</a>'; ?></td>
58 <td style="text-align: center;"><a href="edit-rant.php?rant_id=<?php echo $r->id; ?>">Edit</a></td>
59 <td style="text-align: center;"><a class="delete" href="delete-rant.php?rant_id=<?php echo $r->id; ?>">Delete</a></td>
60 </tr>
61 <?php
62 }
63 ?>
64 </tbody>
65 </table>
66
67 <?php
68 adminfooter();
69 ?>
@@ -0,0 +1,167
1 <?php
2
3 /* This page displays and modifies the Status Box */
4
5 require_once('include/admin.inc.php');
6
7 auth_redirect(); // Require logged in user to access this page.
8
9
10
11
12 /* Handle form submission of new updates */
13
14 function handle_update_form() {
15 global $error,$info,$mtdb;
16
17 check_nonce('update-statusbox');
18 $percent = $_POST['update_percentage'];
19 $eta = strtotime($_POST['update_eta']);
20 $text = $_POST['update_text'];
21
22 $now = time();
23 $percent = trim($percent, "% ");
24 if( !is_numeric ( $percent ) ) {
25 $error = '<p>Percentage complete must be numeric.</p>';
26 return;
27 }
28 if( $percent < 0 || $percent > 100 ) {
29 $error = '<p>Supply percentages between 0 and 100 (inclusive), please.</p>';
30 return;
31 }
32
33 // ETA must be sane
34 if( ($eta < $now && $percent < 100) || ($eta<mktime(0,0,0,1,1,2000) ) ) {
35 $error = '<p>Supply estimated time in the future, please. Current time is ' . date("F j, Y, g:i a", $now) . '</p>';
36 return;
37 }
38
39 $mtdb->query( 'INSERT INTO status (published,eta,percentage,text) VALUES( NOW(), FROM_UNIXTIME(' . (int)$eta . '), '. (int)$percent . ', "' . mysql_real_escape_string($text) . '")' );
40
41 $_POST['update_percentage']=$_POST['update_eta']=$_POST['update_text']='';
42 $info = '<p>Statusbox updated successfully.</p>';
43 }
44
45 if( isset($_POST['action']) && $_POST['action'] == 'create-update' )
46 handle_update_form();
47
48
49
50
51 adminhead('Status Box');
52 adminmenu('manage-statusbox.php');
53
54
55 /* Simple Presets, Select things said before */
56
57
58 $presets = $mtdb->getAll('SELECT COUNT(*) as c, percentage, text, CONCAT( percentage, "% - ", text ) as p FROM status GROUP BY p HAVING c>1 ORDER BY c DESC');
59
60 ?>
61
62
63 <form enctype="multipart/form-data" name="create-update" id="create-update" action="manage-statusbox.php" method="post">
64 <?php nonce_field('update-statusbox'); ?>
65 <input type="hidden" name="action" value="create-update" />
66
67 <h2>Update Status Box</h2>
68 <div class="narrow">
69 <table class="editform" width="100%" cellspacing="2" cellpadding="5">
70
71 <tr>
72 <th scope="row">Current Time</th>
73 <td width="66%"><?php echo date("F j, Y, g:i a"); ?></td>
74 </tr>
75
76 <tr>
77 <th scope="row">Estimated Time Of Next Update</th>
78 <td width="66%"><input name="update_eta" type="text" id="update_eta" value="<?php echo htmlentities($_POST['update_eta']); ?>" /></td>
79 </tr>
80
81 <tr>
82 <th scope="row">Percentage Complete</th>
83 <td width="66%"><input name="update_percentage" type="text" id="update_percentage" value="<?php echo htmlentities($_POST['update_percentage']); ?>" /></td>
84 </tr>
85
86 <tr>
87 <th scope="row">Status Description</th>
88 <td width="66%"><textarea name="update_text" row="6" cols="30" id="update_text"><?php echo htmlentities($_POST['update_text']); ?></textarea></td>
89 </tr>
90
91 <script type="text/javascript">
92 function PresetHandler( f ) {
93
94 var i = f.preset.selectedIndex;
95 var v = f.preset.options[i].value;
96
97 var parts = v.split("% - ");
98
99 if( parts[0] == undefined ) {
100 parts[0] = "";
101 }
102 if( parts[1] == undefined ) {
103 parts[1] = "";
104 }
105
106 f.update_percentage.value = parts[0];
107 f.update_text.value = parts[1];
108
109 return true;
110 }
111 document.write('<tr><th scope="row">Presets</th><td width="66%"><select name="preset" onchange="PresetHandler(this.form);"><option value="">-none-</option><?php
112 foreach( $presets as $p )
113 echo '<option value="' . addslashes(htmlentities($p->p)) . '">' . addslashes(htmlentities($p->p)) . '</option>';
114 ?></select></td></tr>');
115
116 </script>
117 </table>
118
119 <p class="submit"><input type="submit" value="Set Update Status &raquo;" name="submit" /></p>
120 </div>
121 </form>
122
123
124 </div>
125 <div class="wrap">
126
127 <h2>Status Box History</h2>
128 <p>Status updates that have gone before.</p>
129
130 <?php
131
132 $stats = $mtdb->getAll("SELECT published,eta,percentage,text FROM status ORDER BY published DESC limit 5");
133
134 ?>
135
136 <table class="widefat">
137 <thead>
138 <tr>
139 <th scope="col">Published</th>
140 <th scope="col">ETA</th>
141 <th scope="col">Percentage</th>
142 <th scope="col">Text</th>
143 </tr>
144 </thead>
145
146 <tbody id="the-list">
147 <?php
148 $alternate=false;
149 foreach( $stats as $s ) {
150 $alternate=!$alternate;
151 ?>
152 <tr <?php if($alternate) echo 'class="alternate"'; ?>>
153 <th scope="row" style="text-align: center;"><?php echo $s->published; ?></th>
154 <td><?php echo $s->eta; ?></td>
155 <td><?php echo $s->percentage; ?></td>
156 <td><?php echo htmlentities($s->text); ?></td>
157 </tr>
158 <?php
159 }
160 ?>
161 </tbody>
162 </table>
163
164
165 <?php
166 adminfooter();
167 ?>
@@ -0,0 +1,84
1 <?php
2
3 require_once('include/admin.inc.php');
4
5 auth_redirect(); // Require logged in user to access this page.
6
7
8 if( isset($_REQUEST['action']) && 'edit_twitter' == $_REQUEST['action']) {
9 check_nonce('edit-twitter');
10 foreach(array_keys($_REQUEST) as $k) {
11 if(0 !== strpos($k, 'id_'))
12 continue;
13
14 $id = (int) $_REQUEST[$k];
15 $position = (int) $_REQUEST["position_$id"];
16 $msg = $_REQUEST["message_$id"];
17
18 if(0 == $id && !empty($msg)) {
19 // Add a new preset
20 $mtdb->query( sprintf('INSERT INTO twitter_status (position, message) VALUES (%d, "%s")', $position, mysql_real_escape_string($msg)) );
21 adminlog("Added new preset: $msg", MTS_TWITTER, MTA_ADD);
22 } elseif(empty($msg)) {
23 // Delete an existing preset
24 $mtdb->query( "DELETE FROM twitter_status WHERE id = $id" );
25 adminlog("Removed preset: $id", MTS_TWITTER, MTA_ADD);
26 } else {
27 // Modify an existing preset
28 $mtdb->query( sprintf('UPDATE twitter_status SET position = %d, message = "%s" WHERE id = %d', $position, mysql_real_escape_string($msg), $id) );
29 }
30 }
31 }
32
33 $statuses = $mtdb->getAll('SELECT id, position, message FROM twitter_status ORDER BY position, id');
34
35 adminhead('Manage Twitter Presets');
36 adminmenu();
37
38 ?>
39
40 <h2>Manage Twitter Presets</h2>
41 <p>To add a new preset, enter it into the empty box below.</p>
42 <p>To delete a preset, remove all text from its message box.</p>
43
44 <p><a href="post-twitter.php">&lt;- Done</a></p>
45
46 <form method="post" action="manage-twitter-presets.php">
47 <?php nonce_field('edit-twitter'); ?>
48 <input type="hidden" name="action" value="edit_twitter" />
49
50 <table class="widefat">
51 <thead>
52 <tr>
53 <th scope="col" style="width:2em">ID</th>
54 <th scope="col" style="width:4em">Order</th>
55 <th scope="col">Message</th>
56 </tr>
57 </thead>
58 <tbody id="the-list">
59 <?php
60 $alternate=false;
61 foreach($statuses as $k=>$v) {
62 $alternate = !$alternate;
63 ?>
64 <tr <?php if($alternate) echo 'class="alternate"' ?>>
65 <td style="text-align:center"><input type="hidden" name="id_<?php echo $v->id ?>" value="<?php echo $v->id ?>" /><?php echo $v->id ?></td>
66 <td><input type="text" size="3" name="position_<?php echo $v->id ?>" value="<?php echo $v->position ?>" /></td>
67 <td><input type="text" style="width:95%" maxlength="140" name="message_<?php echo $v->id ?>" value="<?php echo $v->message ?>" /></td>
68 </tr>
69 <?php
70 }
71 ?>
72 <tr <?php if(!$alternate) echo 'class="alternate"' ?>>
73 <td style="text-align:center"><input type="hidden" name="id_0" value="0" /></td>
74 <td><input type="text" size="3" name="position_0" value="" /></td>
75 <td><input type="text" style="width:95%" maxlength="140" name="message_0" value="" /></td>
76 </tr>
77 </tbody>
78 </table>
79 <p style="padding-bottom:1em;"><input type="submit" value="Save" /></p>
80 </form>
81
82 <?php
83 adminfooter();
84 ?>
@@ -0,0 +1,156
1 <?php
2
3 require_once('include/admin.inc.php');
4
5 auth_redirect(); // Require logged in user to access this page.
6
7 if( isset($_POST['action']) && $_POST['action'] == 'new' ) {
8 check_nonce('new-twitter-user');
9
10 if(! $mtdb->query( sprintf('INSERT INTO twitter_user(username) VALUES("%s")', mysql_real_escape_string( md5( microtime() )) ) ) ) {
11 adminlog("Error on insertion of new twitter user.", MTS_TWITTER, MTA_INSERT, E_WARNING);
12 mtdie("Error on insertion of new twitter user: ". htmlentities(mysql_error()), 'SQL Error');
13 } else {
14 //$name = sanitize_username($_POST['name']);
15
16 $id = mysql_insert_id();
17
18 $connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET);
19 $request_token = $connection->getRequestToken(OAUTH_CALLBACK . "&id=$id");
20
21 if ($connection->http_code !== 200 ) {
22 adminlog("Twitter getRequestToken failed. HTTP code: $connection->http_code", MTS_TWITTER, MTA_MODIFY);
23 mtdie("Could not connect to twitter.com.");
24 }
25
26 echo $id . '<br/>';
27
28 setOAuthTokens( $id, $request_token['oauth_token'], $request_token['oauth_token_secret'], md5(microtime()) );
29
30 adminlog("New twitter user created successfully.", MTS_TWITTER, MTA_ADD);
31
32 $url = $connection->getAuthorizeURL($request_token['oauth_token']);
33 //echo $url;
34 _redirect($url);
35 exit();
36
37 }
38 }
39
40 if( isset($_REQUEST['action']) && $_REQUEST['action'] == 'twittercallback' && isset($_REQUEST['id'])) {
41 # twitter userID = ID
42 $id = (int)$_REQUEST['id'];
43 $row = $mtdb->getRow( sprintf('SELECT id, username, oauth_token, oauth_token_secret, oauth_access_token FROM twitter_user WHERE id=%d LIMIT 1', $id));
44
45 # Compare token in database with token from twitter. If they differ, bail.
46 if( $row->oauth_token != $_REQUEST['oauth_token'] ) {
47 # token is old, drop from database
48 if(!$mtdb->query("DELETE FROM twitter_user WHERE id = '$id'") ) {
49 adminlog('Error deleting temporary twitter user ' . $id, MTS_TWITTER, MTA_DELETE, E_ERROR);
50 mtdie('Error deleting temporary twitter user.', 'SQL Error');
51 }
52 $error.='<p>OAuth Token are Old</p>';
53 } else {
54 # token is good, save the new Access Token to the database
55 $connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, $row->oauth_token, $row->oauth_token_secret);
56
57 $access_token = $connection->getAccessToken($_REQUEST['oauth_verifier']);
58
59 if (200 == $connection->http_code) {
60 # successful
61 $info.='<p>Successfully obtained OAuth Access Token.</p>';
62 $content = $connection->get('account/verify_credentials');
63 $username = $content->screen_name;
64
65 setOAuthTokens($id, $access_token['oauth_token'], $access_token['oauth_token_secret'], $username);
66 adminlog("Successfully received OAuth Access Tokens for twitter user.", MTS_TWITTER, MTA_MODIFY, E_WARNING);
67
68 //print_r($content);
69
70 } else {
71 # fail
72 if( !$mtdb->query("DELETE FROM twitter_user WHERE id = '$id'") ) {
73 adminlog('Error deleting specified twitter user ' . $id, MTS_TWITTER, MTA_DELETE, E_ERROR);
74 mtdie('Error deleting the specified twitter user.', 'SQL Error');
75 }
76 $info.='<p>Failed to get OAuth Access Token for ' . $username . '.</p>';
77 adminlog("Failed to get OAuth Access Tokens for twitter user.", MTS_TWITTER, MTA_MODIFY, E_ERROR);
78 }
79
80 }
81 }
82
83 $twitter_users = $mtdb->getAll('SELECT id, username, oauth_token, oauth_token_secret, oauth_access_token FROM twitter_user ORDER BY username');
84
85 adminhead('Manage Twitter Users');
86 adminmenu();
87
88 ?>
89
90 <h2>Manage Twitter Users</h2>
91 <p>Make changes to the twitter accounts which we can post to.</p>
92
93 <p><a href="post-twitter.php">&lt;- Done</a></p>
94
95 <table class="widefat">
96 <thead>
97 <tr>
98 <th scope="col" style="text-align: center;">ID #</th>
99 <th scope="col">Twitter.com Username</th>
100 <th scope="col">oauth_token</th>
101 <th scope="col">oauth_token_secret</th>
102 <th scope="col">Authorized</th>
103 <th scope="col"></th>
104 </tr>
105 </thead>
106
107 <tbody id="the-list">
108 <?php
109 $alternate=false;
110 foreach( $twitter_users as $s ) {
111 $alternate=!$alternate;
112
113 ?>
114 <tr id="twitteruser-<?php echo $s->id; ?>" <?php if($alternate) echo 'class="alternate"'; ?>>
115 <th scope="row" style="text-align: center;"><?php echo $s->id; ?></th>
116 <td><?php echo htmlentities($s->username); ?></td>
117 <td><?php echo htmlentities($s->oauth_token); ?></td>
118 <td><?php echo htmlentities($s->oauth_token_secret); ?></td>
119 <td><?php
120 $connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, $s->oauth_token, $s->oauth_token_secret);
121 $content = $connection->get('account/verify_credentials');
122 if( isset($content->profile_image_url)) {
123 echo '<img src="' . $content->profile_image_url . '" />';
124 } else {
125 echo 'Not Authorized';
126 }
127 ?></td>
128 <td style="text-align: center;"><a class="delete" href="delete-twitter-user.php?id=<?php echo (int)$s->id; ?>">Delete</a></td>
129 </tr>
130 <?php
131 }
132 ?>
133 </tbody>
134 </table>
135
136
137 <form enctype="multipart/form-data" name="create-user" id="create-user" action="manage-twitter-users.php" method="post">
138 <?php nonce_field('new-twitter-user'); ?>
139 <input type="hidden" name="action" value="new" />
140
141 <h3>Add Twitter User</h3>
142 <!-- <div class="narrow">
143 <table class="editform" width="100%" cellspacing="2" cellpadding="5">
144 <tr>
145 <th scope="row" width="33%">Username</th>
146 <td width="66%">@<input name="name" type="text" id="name" value="" /></td>
147 </tr>
148 </table>
149 -->
150 <p class="submit"><input type="submit" value="Add Twitter User &raquo;" name="submit" /></p>
151 <!-- </div> -->
152 </form>
153
154 <?php
155 adminfooter();
156 ?>
@@ -0,0 +1,179
1 <?php
2
3 require_once('include/admin.inc.php');
4
5 auth_redirect(); // Require logged in user to access this page.
6
7 if( isset($_GET['delete']) && (int)$_GET['delete'] ) {
8 check_nonce('delete-type-' . (int)$_GET['delete']);
9 if(! $mtdb->query( 'DELETE FROM strip_t WHERE id=' . (int)$_GET['delete'] ) )
10 {
11 adminlog("Error deleting type ".(int)$_GET['delete'], MTS_TYPE, MTA_DELETE, E_WARNING);
12 mtdie("Error on deletion of existing type: " . htmlentities(mysql_error()), 'SQL Error');
13 }
14 if(! $mtdb->query( 'DELETE FROM meta WHERE type=' . (int)$_GET['delete'] ) )
15 {
16 adminlog("Error on deletion of type ".(int)$_GET['delete']."'s metadata.", MTS_TYPE, MTA_DELETE, E_WARNING);
17 mtdie("Error on deletion of existing type's metadata: " . htmlentities(mysql_error()), 'SQL Error');
18 }
19 $info.='<p>Deleted type successfully.<p>';
20 adminlog("Deleted type ".(int)$_GET['delete'], MTS_TYPE, MTA_DELETE);
21 }
22
23 if( isset($_POST['action']) && $_POST['action'] == 'new_type' ) {
24 check_nonce('new-type');
25
26 $name = trim($_POST['name']);
27 $desc = trim($_POST['description']);
28
29 if( check_type_name($name) ) {
30 if(! $mtdb->query( sprintf( 'INSERT INTO strip_t(name, description) VALUES("%s", "%s")', mysql_real_escape_string($name), mysql_real_escape_string($desc)) ) )
31 {
32 adminlog("Error on insertion of new type.", MTS_TYPE, MTA_INSERT, E_WARNING);
33 mtdie("Error on insertion of new type: ". htmlentities(mysql_error()), 'SQL Error');
34 }
35 }
36 $info.='<p>New type created successfully.<p>';
37 adminlog("Type '".$name."' created successfully.", MTS_TYPE, MTA_ADD);
38 }
39
40 if( isset($_POST['action']) && $_POST['action'] == 'edit_type' ) {
41
42 $id = (int)$_POST['type_id'];
43 check_nonce("save-type-$id");
44
45 $name = trim($_POST['name']);
46 $desc = trim($_POST['description']);
47
48 $meta = $_POST['meta'];
49
50 $m_delete = $mtdb->getAll("SELECT meta FROM meta WHERE type = $id");
51
52 $m_insert = array();
53
54 // Key listed in both Insert and Delete lists, so remove from both == Do Nothing
55 foreach( $m_delete as $k=>$v ) {
56 if( array_key_exists( $v->meta, $meta ) ) {
57 unset($m_delete[$k]);
58 unset($meta[$v->meta]);
59 } else {
60 $m_delete[$k] = 'meta=' . (int)$v->meta;
61 }
62 }
63
64 // Key listed only in Insert list, make proper format
65 foreach( $meta as $k=>$v ) {
66 $m_insert[] = "($id," . (int)$k . ')';
67 }
68
69 if( check_type_name( $name ) ) {
70 if( !$mtdb->query( sprintf( 'UPDATE strip_t SET name = "%s", description = "%s" WHERE id = %s', mysql_real_escape_string($name), mysql_real_escape_string($desc), $id)) )
71 {
72 adminlog("Error on updating type ".$id, MTS_TYPE, MTA_UPDATE, E_WARNING);
73 mtdie("Error on update of existing type: ". htmlentities(mysql_error()), 'SQL Error');
74 }
75
76 $sql_insert = "INSERT INTO meta (type,meta) VALUES " . implode(',',$m_insert);
77 $sql_delete = "DELETE FROM meta WHERE type=$id AND ( " . implode(' OR ',$m_delete) . ' )';
78
79 $mtdb->query('START TRANSACTION');
80
81 if( count($m_insert) )
82 if(! $mtdb->query( $sql_insert ) )
83 {
84 adminlog("Error inserting new metatype association data for type ".$id, MTS_TYPE, MTA_INSERT, E_WARNING);
85 mtdie("There was an error inserting new metatype association data. Transaction aborted. $sql_insert");
86 }
87 if( count($m_delete) )
88 if(! $mtdb->query( $sql_delete ) )
89 {
90 adminlog("Error deleting old metatype association data for type ".$id, MTS_TYPE, MTA_REMOVE, E_WARNING);
91 mtdie("There was an error deleting old metatype data. Transaction aborted. $sql_delete");
92 }
93
94 $mtdb->query('COMMIT');
95
96 } else {
97 $error.='<p>Invalid type name!</p>';
98 }
99 $info.='<p>Changes to type saved successfully.<p>';
100 adminlog("Type ".$id." updated.", MTS_TYPE, MTA_UPDATE);
101 }
102
103 //display all types
104 $types = $mtdb->getAll("SELECT strip_t.id AS id, strip_t.name AS name, strip_t.description AS description, COUNT(strip.id) AS strips FROM strip_t LEFT JOIN strip ON strip.type = strip_t.id GROUP BY strip_t.id");
105
106 adminhead('Types');
107 adminmenu();
108
109 ?>
110
111 <h2>Type Management</h2>
112 <p>Make changes to the types which categorize the comics.</p>
113
114 <table class="widefat">
115 <thead>
116 <tr>
117 <th scope="col" style="text-align: center;">Type #</th>
118 <th scope="col">Name</th>
119 <th scope="col">Description</th>
120 <th scope="col">Strips</th>
121 <th scope="col">Metatypes</th>
122 <th scope="col"></th>
123 <th scope="col"></th>
124 </tr>
125 </thead>
126
127 <tbody id="the-list">
128 <?php
129 $alternate=false;
130 foreach( $types as $s ) {
131 $alternate=!$alternate;
132
133 $metas = $mtdb->getAll("SELECT meta_t.name AS name FROM strip_t
134 JOIN meta ON meta.type = strip_t.id JOIN meta_t ON meta.meta = meta_t.id
135 WHERE strip_t.id = $s->id");
136
137 $meta = implode(', ', array_map('_getMetaNameFromObject', $metas) );
138
139 ?>
140 <tr id="comic-<?php echo $s->id; ?>" <?php if($alternate) echo 'class="alternate"'; ?>>
141 <th scope="row" style="text-align: center;"><?php echo $s->id; ?></th>
142 <td><?php echo htmlentities($s->name); ?></td>
143 <td><?php echo htmlentities($s->description); ?></td>
144 <td><?php echo $s->strips ?></td>
145 <td><?php echo htmlentities($meta); ?> </td>
146 <td style="text-align: center;"><a href="edit-type.php?edit=<?php echo (int)$s->id; ?>">Edit</a></td>
147 <td style="text-align: center;"><a class="delete" href="?delete=<?php echo (int)$s->id; ?>">Delete</a></td>
148 </tr>
149 <?php
150 }
151 ?>
152 </tbody>
153 </table>
154
155
156 <form enctype="multipart/form-data" name="create-user" id="create-user" action="manage-types.php" method="post">
157 <?php nonce_field('new-type'); ?>
158 <input type="hidden" name="action" value="new_type" />
159
160 <h2>Create New Type</h2>
161 <div class="narrow">
162 <table class="editform" width="100%" cellspacing="2" cellpadding="5">
163 <tr>
164 <th scope="row" width="33%">Name</th>
165 <td width="66%"><input name="name" type="text" id="name" value="" /></td>
166 </tr>
167 <tr>
168 <th scope="row" width="33%">Description</th>
169 <td width="66%"><input name="description" type="text" id="description" value="" /></td>
170 </tr>
171 </table>
172
173 <p class="submit"><input type="submit" value="Create &raquo;" name="submit" /></p>
174 </div>
175 </form>
176
177 <?php
178 adminfooter();
179 ?>
@@ -0,0 +1,103
1 <?php
2
3 require_once('include/admin.inc.php');
4
5 auth_redirect(); // Require logged in user to access this page.
6
7 $last_type = $mtdb->getOne( 'SELECT type FROM strip ORDER BY id DESC limit 1' );
8 $last_strip_id = $mtdb->getOne( 'SELECT MAX(id) FROM strip' );
9
10 adminhead('Post Comic');
11 adminmenu('post-comic.php');
12
13 $tomorrow = strtotime('tomorrow');
14 $post_date = time();
15
16 if(isset($_REQUEST['next']) && $_REQUEST['next'] == "yes")
17 {
18 //in general, this is the case that is desired
19 // the next monday, wednesday, or friday that isn't today
20 $post_date = min( strtotime("next Monday +1 hour", $tomorrow), strtotime("next Wednesday +1 hour", $tomorrow), strtotime("next Friday +1 hour", $tomorrow) );
21
22 //however, if it is monday, wednesday, or friday AND before 1 AM
23 // then we want to post at 1 AM on this day
24 $today = date("l");
25 if(($today == "Monday" || $today == "Wednesday" || $today == "Friday") && date("G") == 0)
26 {
27 $post_date = "today +1 hour";
28 }
29 }
30
31 ?>
32
33 <h2>Post New Comic</h2>
34
35 <form enctype="multipart/form-data" action="edit-comic.php" method="post" name="post" id="post">
36 <?php nonce_field('new-strip'); ?>
37 <input type="hidden" name="action" value="new_comic" />
38 <div id="poststuff">
39
40 <div id="moremeta">
41 <div id="grabit" class="dbx-group">
42
43 <fieldset id="slugdiv" class="dbx-box">
44 <h3 class="dbx-handle">Comic Type</h3>
45 <div class="dbx-content"><select name="strip_type">
46 <?php
47 $types = $mtdb->getAll( 'SELECT id, description FROM strip_t ORDER BY id' );
48 foreach( $types as $k=>$v )
49 printf('<option value="%s" %s>%s</option>', htmlentities($v->id), ($last_type == $v->id ? 'selected="selected"' : '' ), $v->description);
50 ?>
51 </select></div>
52 </fieldset>
53
54 <fieldset id="pubdatediv" class="dbx-box">
55 <h3 class="dbx-handle">Post Date</h3>
56 <div class="dbx-content"> <input type="text" name="strip_date" value="<?php echo date('Y-m-d H:i:s', $post_date); ?>" /> </div>
57 </fieldset>
58
59 <fieldset id="pubdatediv" class="dbx-box">
60 <h3 class="dbx-handle">Strip Number</h3>
61 <div class="dbx-content"> <input type="text" name="strip_new_id" size="6" value="<?php echo $last_strip_id + 1; ?>" id="strip_id" /> </div>
62 </fieldset>
63
64 <fieldset id="stripdiv" class="dbx-box">
65 <h3 class="dbx-handle">Upload Comic</h3>
66 <div class="dbx-content">
67 <input type="hidden" name="MAX_FILE_SIZE" value="10000000" />
68 <input name="comicFile" type="file" tabindex="2" size="12" />
69 </div>
70 </fieldset>
71
72 <fieldset id="bookpagenumberdiv" class="dbx-box">
73 <h3 class="dbx-handle">Book Page Number</h3>
74 <div class="dbx-content"> <input type="text" name="book" size="3" value="" />-<input type="text" name="page" size="4" value=""/> </div>
75 </fieldset>
76
77 </div>
78 </div>
79
80 <fieldset id="titlediv">
81 <legend>Title</legend>
82 <div><input type="text" name="strip_title" size="40" tabindex="1" value="" id="title" /></div>
83 </fieldset>
84
85 <fieldset id="postdivrich">
86 <legend>Transcript</legend>
87 <style type="text/css">
88 #postdivrich table, #postdivrich #quicktags {border-top: none;}
89 #quicktags {border-bottom: none; padding-bottom: 2px; margin-bottom: -1px;}
90 #edButtons {border-bottom: 1px solid #ccc;}
91 </style>
92 <div><textarea class="mceEditor" rows="27" cols="40" name="content" tabindex="3" id="content"></textarea></div>
93 </fieldset>
94
95 <p class="submit">
96 <input name="post_comic" type="submit" id="post_comic" tabindex="4" accesskey="p" value="Post Comic" />
97 </p>
98
99 </div>
100 </form>
101 <?php
102 adminfooter();
103 ?>
@@ -0,0 +1,104
1 <?php
2
3 /* This is a blank form for new pages to be started.
4 It does not read past page information.
5 Some fields will be prefilled based on current author. */
6
7 require_once('include/admin.inc.php');
8
9 auth_redirect(); // Require logged in user to access this page.
10
11 adminhead('Write Static Page');
12 adminmenu('post-page.php');
13
14 ?>
15 <script language="javascript" type="text/javascript" src="include/tiny_mce/tiny_mce.js"></script>
16 <script language="javascript" type="text/javascript">
17 tinyMCE.init({
18 mode : "exact",
19 elements: "content",
20 theme : "advanced",
21 theme_advanced_buttons1 : "bold,italic,underline,separator,strikethrough,justifyleft,justifycenter,justifyright,justifyfull,bullist,numlist,undo,redo,link,unlink,code,formatselect",
22 theme_advanced_buttons2 : "",
23 theme_advanced_buttons3 : "",
24 theme_advanced_toolbar_location : "top",
25 theme_advanced_toolbar_align : "left",
26 theme_advanced_path_location : "bottom",
27 extended_valid_elements : "a[name|href|target|title|onclick],img[class|src|border=0|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name],hr[class|width|size|noshade],font[face|size|color|style],span[class|align|style]",
28 theme_advanced_blockformats : "p,h3,h4,h5,h6"
29 });
30 </script>
31 <h2>Create New Page</h2>
32
33 <form enctype="multipart/form-data" action="edit-page.php" method="post" name="post" id="post">
34 <?php nonce_field('new-page'); ?>
35 <input type="hidden" name="action" value="new_page" />
36
37 <div id="poststuff">
38
39 <div id="moremeta">
40 <div id="grabit" class="dbx-group">
41
42 <fieldset id="pagenamediv" class="dbx-box">
43 <h3 class="dbx-handle">Page URL Name</h3>
44 <div class="dbx-content">
45 <input type="text" name="page_name" />
46 </div>
47 </fieldset>
48
49 <fieldset id="statusdiv" class="dbx-box">
50 <h3 class="dbx-handle">Published Status</h3>
51 <div class="dbx-content">
52 <label><input type="radio" name="page_status" value="draft" checked="checked"/>Draft</label>
53 <label><input type="radio" name="page_status" value="published"/>Published</label>
54 </div>
55 </fieldset>
56
57 </div>
58 </div>
59
60 <fieldset id="titlediv">
61 <legend>Title</legend>
62 <div><input type="text" name="title" size="40" tabindex="1" value="" id="title" /></div>
63 </fieldset>
64
65 <fieldset id="postdivrich">
66 <legend>Page</legend>
67
68 <style type="text/css">
69 #postdivrich table, #postdivrich #quicktags {border-top: none;}
70 #quicktags {border-bottom: none; padding-bottom: 2px; margin-bottom: -1px;}
71 #edButtons {border-bottom: 1px solid #ccc;}
72 </style>
73 <div><textarea class="mceEditor" rows="13" cols="40" name="content" tabindex="3" id="content"></textarea></div>
74 </fieldset>
75
76
77 <p class="submit">
78 <input name="save" type="submit" id="save" tabindex="3" value="Save and Continue Editing" style="font-weight: bold;" />
79 <input name="publish" type="submit" id="publish" tabindex="5" accesskey="p" value="Publish" />
80 </p>
81
82
83
84 <div class="dbx-b-ox-wrapper">
85
86 <fieldset id="cssdivrich">
87 <legend>Optional CSS</legend>
88
89 <style type="text/css">
90 #postdivrich table, #postdivrich #quicktags {border-top: none;}
91 #quicktags {border-bottom: none; padding-bottom: 2px; margin-bottom: -1px;}
92 #edButtons {border-bottom: 1px solid #ccc;}
93 </style>
94 <div><textarea rows="13" cols="40" name="style" tabindex="6" id="style"></textarea></div>
95 </fieldset>
96
97 </div>
98
99
100 </div>
101
102 </form>
103
104 <?php adminfooter() ?>
@@ -0,0 +1,194
1 <?php
2
3 /* This is a blank form for new rants to be started.
4 It does not read past rant information.
5 Some fields will be prefilled based on current author. */
6
7 require_once('include/admin.inc.php');
8
9 auth_redirect(); // Require logged in user to access this page.
10
11 adminhead('Write Rant');
12 adminmenu('post-rant.php');
13
14 $rant_image_ext = $mtdb->getOne( 'SELECT extension FROM media_t WHERE id=' . (int)$currentuser->imagetype );
15
16 ?>
17
18 <script language="javascript" type="text/javascript" src="include/tiny_mce/tiny_mce.js"></script>
19 <script language="javascript" type="text/javascript">
20 tinyMCE.init({
21 mode : "textareas",
22 theme : "advanced",
23 theme_advanced_buttons1:"bold,italic,underline,strikethrough,|,bullist,numlist,blockquote,|,justifyleft,justifycenter,justifyright,justifyfull,|,link,unlink,|,image,media,charmap,|,formatselect,forecolor,removeformat,|,pastetext,pasteword,|,outdent,indent,|,undo,redo,|,code,visualchars,|,fullscreen,preview",
24 theme_advanced_buttons2:"",
25 theme_advanced_buttons3 : "",
26 plugin_preview_width : "350",
27 plugin_preview_height : "700",
28 language:"en",
29 theme_advanced_toolbar_location:"top",
30 theme_advanced_toolbar_align:"left",
31 theme_advanced_statusbar_location:"bottom",
32 theme_advanced_resizing:"1",
33 theme_advanced_resize_horizontal:"",
34 paste_convert_middot_lists:"1",
35 paste_remove_spans:"1",
36 paste_remove_styles:"1",
37 gecko_spellcheck:"1",
38 extended_valid_elements : "a[name|href|target|title|onclick],img[class|src|border=0|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name],hr[class|width|size|noshade],font[face|size|color|style],span[class|align|style]",
39 theme_advanced_blockformats : "p,h3,h4,h5,h6",
40 plugins:"safari,inlinepopups,autosave,paste,media,fullscreen,contextmenu,advimage,advlink,visualchars,preview"
41 });
42 </script>
43
44 <h2>Create New Rant</h2>
45
46 <form enctype="multipart/form-data" action="edit-rant.php" method="post" name="post" id="post">
47 <?php nonce_field('new-rant'); ?>
48 <input type="hidden" name="rant_id" value="" />
49 <input type="hidden" name="action" value="new_rant" />
50
51 <div id="poststuff">
52
53 <div id="moremeta">
54 <div id="grabit" class="dbx-group">
55
56 <fieldset id="slugdiv" class="dbx-box">
57 <h3 class="dbx-handle">Side</h3>
58 <div class="dbx-content"><select name="rant_side">
59 <?php
60 // What side does this author usually post on?
61 $usual = $mtdb->getOne( 'SELECT side,count(*) c FROM rant WHERE author=' . (int)$currentuser->id . ' GROUP BY side ORDER BY c DESC limit 1' );
62
63 $sides = array('left'=>'Left','right'=>'Right');
64 foreach( $sides as $k=>$v ) {
65 printf('<option value="%s" %s>%s</option>', htmlentities($k), ($usual == $k ? 'selected="selected"' : '' ), $v );
66 }
67 ?>
68 </select></div>
69 </fieldset>
70
71 <fieldset id="authordiv" class="dbx-box">
72 <h3 class="dbx-handle">Author</h3>
73 <div class="dbx-content"><select name="rant_author"><?php
74 $contrib = $mtdb->getAll('select id,name from contributor');
75 foreach( $contrib as $k=>$v ) {
76 printf('<option value="%s" %s>%s</option>', htmlentities($v->id), ( $currentuser->id == $v->id ? 'selected="selected"' : '' ), $v->name );
77 } ?>
78 </select></div>
79 </fieldset>
80
81 <fieldset id="pubdatediv" class="dbx-box">
82 <h3 class="dbx-handle">Post Date</h3>
83 <div class="dbx-content"> <input type="text" name="rant_date" value="<?php echo date('Y-m-d H:i:s'); ?>" /> </div>
84 </fieldset>
85
86 <fieldset id="statusdiv" class="dbx-box">
87 <h3 class="dbx-handle">Published Status</h3>
88 <div class="dbx-content">
89 <label><input type="radio" name="rant_status" value="draft" checked="checked"/>Draft</label>
90 <label><input type="radio" name="rant_status" value="published"/>Published</label>
91 </div>
92 </fieldset>
93
94 </div>
95 </div>
96
97 <fieldset id="titlediv">
98 <legend>Title</legend>
99 <div><input type="text" name="title" size="40" tabindex="1" value="" id="title" /></div>
100 </fieldset>
101
102 <fieldset id="linkdiv">
103 <legend>Link</legend>
104 <div><input type="text" name="link" size="40" tabindex="2" value="<?php echo htmlentities( $currentuser->default_link ); ?>" id="link" /></div>
105 </fieldset>
106
107 <fieldset id="postdivrich">
108 <legend>Post</legend>
109
110 <style type="text/css">
111 #postdivrich table, #postdivrich #quicktags {border-top: none;}
112 #quicktags {border-bottom: none; padding-bottom: 2px; margin-bottom: -1px;}
113 #edButtons {border-bottom: 1px solid #ccc;}
114 </style>
115 <div><textarea class="mceEditor" rows="13" cols="40" name="content" tabindex="3" id="content"></textarea></div>
116
117
118 <?php
119 /*
120 include("include/fckeditor/fckeditor_php4.php");
121 $oFCKeditor = new FCKeditor('content');
122 $oFCKeditor->BasePath = 'include/fckeditor/';
123 $oFCKeditor->Value = '';
124 $oFCKeditor->Create();
125 */
126 ?>
127
128
129
130 </fieldset>
131
132
133
134 <p class="submit">
135 <input name="save" type="submit" id="save" tabindex="3" value="Save and Continue Editing" style="font-weight: bold;" />
136 <input name="publish" type="submit" id="publish" tabindex="5" accesskey="p" value="Publish" />
137 </p>
138
139
140
141 <div class="dbx-b-ox-wrapper">
142
143 <fieldset id="rant-image" class="dbx-box">
144 <h3 class="dbx-handle">Image</h3>
145 <div>
146 <table border="0" cellpadding="4">
147 <tr><td valign="top" width="40%">
148 <p><?php
149
150 // no image in place yet
151 $rantimage_filename = SITE_RANT.'/' . $currentuser->default_image;
152 if( file_exists( SITE_PATH_ABS.'/' . $rantimage_filename )) {
153 echo 'Currently using default rant image for this contributor. <a href="user-edit.php?edit='.$currentuser->id.'">Change default</a>.';
154 } else {
155 echo $rantimage_filename;
156 $rantimage_filename = false;
157 echo 'There is currently no image associated with this rant, <br/>and no default rant image associated with this contributor.
158 <br/><a href="user-edit.php?edit=' . $currentuser->id . '">Add a default rant image to your profile.</a>';
159 }
160 ?>
161 </p>
162 <p>Upload a rant image:<br/>
163 <input type="hidden" name="MAX_FILE_SIZE" value="10000000" />
164 <input name="ranterImage" type="file"/>
165 </p>
166
167 </td><td>
168 <?php if ( $rantimage_filename ): ?>
169 <p><img src="<?php echo SITE_HOST . '/' . SITE_PATH . '/' . $rantimage_filename; ?>" width="150" /></p>
170 <?php endif; ?>
171 </td></tr>
172 <tr><td>
173 <p>Rant image alt text:</p>
174 <input type="text" name="rant_imagetext" size="40" tabindex="2" value="" id="rant_imagetext" />
175 </td></tr>
176 <tr id="rant_attachments"><td>
177 <p>Attach files:</p>
178 <ol id="rant_attachment_list">
179 </ol>
180 <script src="include/rants.js" type="text/javascript"></script>
181 <a href="#rant_attachments" onclick="new_rant_attachment()">(add attachment)</a>
182 </td></tr>
183 </table>
184 </div>
185 </fieldset>
186
187 </div>
188
189
190 </div>
191
192 </form>
193
194 <?php adminfooter() ?>
@@ -0,0 +1,14
1 <?php
2
3 require_once('include/admin.inc.php');
4
5 auth_redirect(); // Require logged in user to access this page.
6
7 check_nonce('new-scratchpad');
8
9 $mtdb->query( sprintf( 'INSERT INTO scratchpad (contributor, message) VALUES (%d, "%s")', (int)$currentuser->id, mysql_real_escape_string($_REQUEST['message'])) );
10
11 adminlog("User posted to scratchpad.", MTS_SCRATCH, MTA_INSERT);
12 _redirect( ADMIN_PATH . '/index.php' );
13
14 ?>
@@ -0,0 +1,148
1 <?php
2
3 require_once('include/admin.inc.php');
4
5 auth_redirect(); // Require logged in user to access this page.
6
7
8 if('post_twitter' == $_REQUEST['action'])
9 {
10 check_nonce('new-twitter');
11
12 $postmessage = '';
13 if(!empty($_REQUEST['stdmessage']) ) $postmessage = trim($_REQUEST['stdmessage']);
14 if( strlen($_REQUEST['message']) ) $postmessage = trim($_REQUEST['message']);
15
16 #string replacement macros
17 $next_strip_id = $mtdb->getOne( 'SELECT MAX(id) FROM strip' );
18 $next_strip_id += 1;
19 $postmessage = str_replace("#nextcomic", $next_strip_id, $postmessage);
20
21 if('' == $postmessage) _redirect( ADMIN_PATH . '/post-twitter.php?tweet=missing');
22 $username = sanitize_username($_REQUEST['twitter_user']);
23 $postasuser = $mtdb->getOne( sprintf('SELECT username FROM twitter_user WHERE username="%s"', mysql_real_escape_string($username)));
24
25 if( in_array('twitter', $_REQUEST['service']) )
26 $rc = twitterpost( numeric_entities(utfentities($postmessage)), $postasuser );
27 if( in_array('rss', $_REQUEST['service']) )
28 $rc = rsspost( numeric_entities(utfentities($postmessage)), SITE_HOST.SITE_PATH );
29
30 if($rc) _redirect( ADMIN_PATH . '/post-twitter.php?tweet=success');
31 _redirect( ADMIN_PATH . '/post-twitter.php?tweet=fail');
32
33 // Shall not pass, all routes lead to redirect.
34 }
35
36 if( isset($_REQUEST['tweet']) && 'success' == $_REQUEST['tweet'] )
37 $info.='Status successfully posted to Twitter.';
38
39 if( isset($_REQUEST['tweet']) && 'fail' == $_REQUEST['tweet'] )
40 $info.='Status could not be posted to Twitter. Is it up?';
41
42 if( isset($_REQUEST['tweet']) && 'missing' == $_REQUEST['tweet'] )
43 $error.='Oops~ Looks like you forgot to enter a message.';
44
45
46 $statuses = $mtdb->getAll('SELECT id, position, message FROM twitter_status ORDER BY position, id');
47 $twitter_users = $mtdb->getAll('SELECT id, username, oauth_token, oauth_token_secret, oauth_access_token FROM twitter_user ORDER BY username');
48
49 adminhead('Update Twitter');
50 adminmenu();
51
52 ?>
53
54 <h2>Update Twitter</h2>
55 <form name="statusform" method="post" action="post-twitter.php">
56 <?php nonce_field('new-twitter'); ?>
57 <input type="hidden" name="action" value="post_twitter" />
58 <script type="text/javascript" src="<?php echo SITE_HOST.SITE_PATH; ?>/resources.js"></script>
59
60 </ul>
61
62 <p>Post As: <select name="twitter_user">
63 <?php foreach($twitter_users as $k=>$v) {
64 printf( '<option %s value="%s">%s</option>', ($v->username == TWITTER_USER ? 'selected="selected"' : '') , htmlentities($v->username), htmlentities($v->username) );
65 }
66 ?>
67 </select>
68 <a href="manage-twitter-users.php">Edit</a>
69 </p>
70 <p>Message Preset: <select name="stdmessage" onChange="copyPreset()">
71 <option value=""></option>
72 <!-- TODO: Javascript to copy the preset downward, so it can be edited. -->
73 <?php foreach($statuses as $k=>$v) {
74 printf( '<option value="%s">%s</option>', htmlentities($v->message), htmlentities($v->message) );
75 } ?>
76 </select>
77 <a href="manage-twitter-presets.php">Edit</a>
78 </p>
79 <p><textarea cols="70" rows="2" id="statusmessage" name="message" maxlength="140" size="140" onKeyDown="charCounter();" onKeyUp="charCounter();"></textarea> <input type="submit" value="Send" /></p>
80 <p style="padding-bottom:1em;">Characters remaining: <span id="charactersremaining">140</span>
81 <p>
82 Post to:
83 <label><input type="checkbox" name="service[]" value="twitter" selected="selected" checked="checked" /> Twitter</label>
84 <label><input type="checkbox" name="service[]" value="rss" /> RSS</label>
85 </p>
86 </form>
87
88 <script type="text/javascript">
89 <!--
90 function copyPreset() {
91 var preset = document.statusform.stdmessage;
92 var status = document.statusform.message
93 status.value = preset.options[preset.selectedIndex].value
94 charCounter()
95 }
96 function charCounter() {
97 var status = document.statusform.message
98 var charactersremaining = document.getElementById('charactersremaining');
99 charactersremaining.innerHTML = 140 - status.value.length
100 }
101 -->
102 </script>
103
104 <?php /*?>
105 <script type="text/javascript" src="http://twitter.com/statuses/user_timeline/<?php echo TWITTER_USER; ?>.json?callback=mtCallback&amp;count=3"></script> */ ?>
106
107 <hr/>
108 <script src="http://widgets.twimg.com/j/2/widget.js"></script>
109 <table border="0"><tr>
110 <?php foreach($twitter_users as $k=>$v) { ?>
111 <td>
112 <script>
113 new TWTR.Widget({
114 version: 2,
115 type: 'profile',
116 rpp: 4,
117 interval: 6000,
118 width: 250,
119 height: 300,
120 theme: {
121 shell: {
122 background: '#ffffff',
123 color: '#000000'
124 },
125 tweets: {
126 background: '#f9fcfc',
127 color: '#000000',
128 links: '#0000ff'
129 }
130 },
131 features: {
132 scrollbar: false,
133 loop: false,
134 live: false,
135 hashtags: true,
136 timestamp: true,
137 avatars: false,
138 behavior: 'all'
139 }
140 }).render().setUser('<?php echo $v->username; ?>').start();
141 </script>
142 </td>
143 <?php } ?>
144 </tr></table>
145
146 <?php
147 adminfooter();
148 ?>
@@ -0,0 +1,36
1 <?php
2
3 require_once('include/admin.inc.php');
4
5 auth_basic();
6
7 $count = isset($_REQUEST['count']) && ctype_digit($_REQUEST['count']) ? $_REQUEST['count'] : 25;
8
9 $entries = $mtdb->getAll("SELECT UNIX_TIMESTAMP(l.logdate) AS logdate, c.name AS cname, c.email AS cmail, s.name AS section, action, level, message FROM admin_log l JOIN admin_section s ON l.section = s.id LEFT JOIN contributor c ON l.contributor = c.id ORDER BY l.logdate DESC LIMIT $count");
10
11 header("Content-Type: application/rss+xml;charset=utf-8");
12
13 echo "<?xml version=\"1.0\" ?>\n";
14 ?>
15 <rss version="2.0">
16 <channel>
17 <title>Megatokyo Admin Log</title>
18 <link>http://www.megatokyo.com/admin</link>
19 <description>Listing of administrative events: errors, warnings, and notifications.</description>
20 <language>en-us</language>
21
22 <?php foreach($entries as $k=>$v) { ?>
23 <item>
24 <title><?php echo htmlentities($v->message, ENT_COMPAT, 'UTF-8') ?></title>
25 <author><?php printf('%s (%s)', $v->cmail, $v->cname) ?></author>
26 <pubDate><?php echo date( DATE_RFC822, $v->logdate ) ?></pubDate>
27 <guid><?php printf('%s%s/%s/view-adminlog.php?timestamp=%d', SITE_HOST, SITE_PATH, SITE_ADMIN, $v->logdate) ?></guid>
28
29 <category domain="<?php printf('%s%s/%s/log-levels', SITE_HOST, SITE_PATH, SITE_ADMIN) ?>"><?php echo $v->level ?></category>
30 <category domain="<?php printf('%s%s/%s/log-section', SITE_HOST, STE_PATH, SITE_ADMIN) ?>"><?php echo $v->section ?></category>
31 <category domain="<?php printf('%s%s/%s/log-acion', SITE_HOST, SITE_PATH, SITE_ADMIN) ?>"><?php echo $v->action ?></category>
32 <description><?php echo htmlentities($v->message, ENT_COMPAT, 'UTF-8') ?></description>
33 </item>
34 <?php } ?>
35 </channel>
36 </rss>
@@ -0,0 +1,33
1 <?php
2
3 require_once('include/admin.inc.php');
4
5 auth_basic();
6
7 $count = isset($_REQUEST['count']) && ctype_digit($_REQUEST['count']) ? $_REQUEST['count'] : 25;
8
9 $entries = $mtdb->getAll("SELECT UNIX_TIMESTAMP(s.published) AS pubdate, c.name AS cname, c.email AS cmail, message FROM scratchpad s JOIN contributor c ON s.contributor = c.id ORDER BY s.published DESC LIMIT $count");
10
11 header("Content-Type: application/rss+xml;charset=utf-8");
12
13 echo "<?xml version=\"1.0\" ?>\n";
14 ?>
15 <rss version="2.0">
16 <channel>
17 <title>Megatokyo Admin Scratchpad</title>
18 <link>http://www.megatokyo.com/admin</link>
19 <description>Listing of administrative events: errors, warnings, and notifications.</description>
20 <language>en-us</language>
21
22 <?php foreach($entries as $k=>$v) { ?>
23 <item>
24 <title><?php echo $v->cname, ': ', htmlentities($v->message, ENT_COMPAT, 'UTF-8') ?></title>
25 <author><?php printf('%s (%s)', $v->cmail, $v->cname) ?></author>
26 <pubDate><?php echo date( DATE_RFC822, $v->pubdate ) ?></pubDate>
27 <guid><?php printf('%s%s/%s/?timestamp=%d', SITE_HOST, SITE_PATH, SITE_ADMIN, $v->pubdate) ?></guid>
28
29 <description><?php echo $v->cname, ': ', htmlentities($v->message, ENT_COMPAT, 'UTF-8') ?></description>
30 </item>
31 <?php } ?>
32 </channel>
33 </rss>
@@ -0,0 +1,31
1 <?php
2
3 require_once('include/admin.inc.php');
4
5 $count = isset($_REQUEST['count']) && ctype_digit($_REQUEST['count']) ? $_REQUEST['count'] : 25;
6
7 $entries = $mtdb->getAll("SELECT UNIX_TIMESTAMP(l.logdate) AS logdate, s.name AS section, action, message FROM admin_log l JOIN admin_section s ON l.section = s.id WHERE s.name = 'strip' ORDER BY l.logdate DESC LIMIT $count");
8
9 header("Content-Type: application/rss+xml;charset=utf-8");
10
11 echo "<?xml version=\"1.0\" ?>\n";
12 ?>
13 <rss version="2.0">
14 <channel>
15 <title>Megatokyo Admin Log</title>
16 <link>http://www.megatokyo.com/admin</link>
17 <description>Listing of administrative events: errors, warnings, and notifications.</description>
18 <language>en-us</language>
19
20 <?php foreach($entries as $k=>$v) { ?>
21 <item>
22 <title><?php echo htmlentities($v->message, ENT_COMPAT, 'UTF-8') ?></title>
23 <author><?php printf('%s (%s)', $v->cmail, $v->cname) ?></author>
24 <pubDate><?php echo date( DATE_RFC822, $v->logdate ) ?></pubDate>
25 <guid><?php printf('%s%s/%s/view-adminlog.php?timestamp=%d', SITE_HOST, SITE_PATH, SITE_ADMIN, $v->logdate) ?></guid>
26 <category domain="<?php printf('%s%s/%s/log-acion', SITE_HOST, SITE_PATH, SITE_ADMIN) ?>"><?php echo $v->action ?></category>
27 <description><?php echo htmlentities($v->message, ENT_COMPAT, 'UTF-8') ?></description>
28 </item>
29 <?php } ?>
30 </channel>
31 </rss>
@@ -0,0 +1,58
1 <?php
2
3 require_once('include/admin.inc.php');
4
5 auth_redirect(); // Require logged in user to access this page.
6
7 if($_POST)
8 {
9 check_nonce('swap-strip');
10
11 if(!is_numeric($_POST['comic_a']) || !is_numeric($_POST['comic_b']))
12 mtdie('This tool only works on numeric strip numbers.');
13
14 $a = (int)$_POST['comic_a'];
15 $b = (int)$_POST['comic_b'];
16
17 $f = fopen(SITE_PATH_ABS.'/'.SITE_STRIP.'/'.SITE_STRIP_LOCK, 'w');
18 flock($f, LOCK_EX);
19
20 swap_strips( $a, $b );
21
22 close($f);
23
24 $info.='<p>Strips $a and $b swapped successfully.</p>';
25 adminlog("Strips $a and $b have been swapped.", MTS_STRIP, MTA_MODIFY);
26 }
27
28
29
30 adminhead('Swap Comics');
31 adminmenu('swap-comics.php');
32
33 ?>
34
35 <h2>Swap Comics</h2>
36
37 <form action="swap-comics.php" method="post" name="post" id="post">
38
39 <div id="poststuff">
40
41 <table class="editform" width="100%" cellspacing="2" cellpadding="5">
42 <tr>
43 <th scope="row" width="33%">First Comic</th>
44 <td width="66%"><input name="comic_a" type="text" id="comic_a" value="" /></th>
45 </tr>
46 <tr>
47 <th scope="row" width="33%">Second Comic</th>
48 <td width="66%"><input name="comic_b" type="text" id="comic_b" value="" /></th>
49 </tr>
50 </table>
51
52 <p class="submit"><input type="submit" value="Swap &raquo;" name="submit" /></p>
53
54 </div>
55
56 </form>
57
58 <?php adminfooter() ?>
@@ -0,0 +1,43
1 <?php
2
3 require_once('include/admin.inc.php');
4
5 // First, the quick hack way. May become neccessary to parallelize later.
6
7 $tweets = $mtdb->getAll("SELECT username, password, text, status, twitter_post.id AS id
8 FROM twitter_post JOIN twitter_user
9 ON twitter_post.user = twitter_user.id
10 WHERE twitter_post.status = 'scheduled'
11 AND time >= NOW()
12 AND time < TIMESTAMPADD(" . RUN_INTERVAL . ", NOW())
13 ");
14
15 // Check if we actually have any tweets. If not, bail.
16 if(count($tweets) === 0)
17 {
18 exit(0);
19 }
20
21 // There are tweets to post. Let's get to work.
22
23 foreach($tweets as $t)
24 {
25 // Lock the tweet
26 $mtdb->query("UPDATE twitter_post SET status = 'locked' WHERE id = ".(int)$t->id." AND status = 'scheduled'", false);
27
28 if(twitterpost($t->text, $t->username, $t->password))
29 {
30 // It worked!
31 adminlog("Scheduled tweet posted for user ".$t->username, MTS_TWITTER, MTA_ADD);
32 $t->status = 'success';
33 }
34 else
35 {
36 // Well, shit. Something went wrong. Log it.
37 adminlog("Error $ret_code posting scheduled tweet ".$t->id . ' with return value ' . $ret, MTS_TWITTER, MTA_ADD);
38 $t->status = 'error';
39 }
40
41 // Unlock tweet, update db.
42 $mtdb->query("UPDATE twitter_post SET status = '".mysql_real_escape_string($t->status)."' WHERE status = 'locked' AND id = ".(int)$t->id, false);
43 }
@@ -0,0 +1,179
1 <?php
2
3 require_once('include/admin.inc.php');
4
5 auth_redirect(); // Require logged in user to access this page.
6
7
8
9 if( isset($_POST['edit']) ) {
10
11 if( $_POST['edit'] === 'NEW' ) {
12 $username = sanitize_username( $_POST['user_login'] );
13 if( $username != $_POST['user_login'] || strlen($_POST['user_login']) < 1 )
14 mtdie( 'The specified username is not valid. Must be composed of a-z _ - @ .', 'Invalid Username' );
15
16 copy(RANTIMG.'default', RANTIMG.$username.'.png');
17
18 $mtdb->query( 'INSERT INTO contributor (name, default_image) VALUES ("' . mysql_real_escape_string($username) . '", "'.$username.'.png")' );
19 $user = get_userdatabylogin( $username );
20 $userid = $user->id;
21 $info.='<p>User Account Created</p>';
22 adminlog("User '".$username."' created.", MTS_USER, MTA_ADD);
23 $user_old = $user;
24 } else {
25 $userid = (int) $_POST['edit'];
26 $user_old = $user = get_userdatabyid( $userid );
27 }
28
29 $user->nameplate = $_POST['nickname'];
30 $user->default_image = $user_old->default_image;
31 $user->default_link = $_POST['rant-link'];
32 $user->email = $_POST['email'];
33
34 if( !empty($_POST['password_new1']) && !empty($_POST['password_new2']) ) {
35
36 if( $_POST['password_new1'] !== $_POST['password_new2'] ) {
37 $error.='<p>New passwords do not match.</p>';
38 } else {
39 /* password change */
40 if( ! $mtdb->getOne( 'SELECT id FROM contributor WHERE id = "' . (int)$user->id . '" AND (password = SHA1("' . mysql_real_escape_string($_POST['password_old']) . '") OR password = "")' )) {
41 $error.='<p>Specified password is incorrect.</p>';
42 } else {
43 /* Password match */
44 $user->password = $_POST['password_new1'];
45 change_password( $user );
46 $info.='<p>Password successfully changed.</p>';
47 }
48 }
49 }
50
51 function handle_upload( &$user ) {
52 global $info,$error;
53
54 if( !$_FILES['rant_image'] ) return;
55
56 if( '' == $_FILES['rant_image']['name'] ) return;
57 if( UPLOAD_ERR_NO_FILE == $_FILES['rant_image']['error'] ) return;
58 if( 0 == $_FILES['rant_image']['size'] ) return;
59
60 $info.='<p>Tried to upload an image.</p>';
61 // Uploading new rant image
62 $imagedata = getimagesize($_FILES['rant_image']['tmp_name']);
63 if( 300 !== $imagedata[0] ) {
64 $error.='<p>Image wrong width: '.$imagedata[0].'</p>';
65 return;
66 }
67 if( 245 !== $imagedata[1]) {
68 $error.='<p>Image wrong height: '.$imagedata[1].'</p>';
69 return;
70 }
71
72 switch( $_FILES['rant_image']['type'] ) {
73 case 'image/jpeg':
74 case 'image/jpg': $ext = 'jpg'; break;
75 case 'image/gif': $ext = 'gif'; break;
76 case 'image/png': $ext = 'png'; break;
77 case 'image/bmp': $ext = 'bmp'; break;
78 case 'image/tiff': $ext = 'tiff'; break;
79 default:
80 $error.='<p>Unknown image extension. Upload refused.</p>';
81 return;
82 }
83
84 $destination_path = $user->name.'.'.$ext;
85 if( !is_uploaded_file( $_FILES['rant_image']['tmp_name'] )) {
86 $error.='<p>Something went wrong while retrieving the uploaded image.</p>';
87 return;
88 }
89 if( move_uploaded_file($_FILES['rant_image']['tmp_name'], RANTIMG.$destination_path) ) { // TODO: SITE_PATH_ABS .'/'. SITE_RANT ?
90 // great
91 $user->default_image = $destination_path;
92 $info.='<p>New rant image uploaded.</p>';
93 } else {
94 $error.='<p>Something went wrong while storing the uploaded image.</p>';
95 adminlog("File system error while uploading rant image.", MTS_USER, MTA_MODIFY, E_WARNING);
96 }
97 }
98
99 handle_upload( $user );
100 save_userdata( $user );
101 $info.='<p>Changes to user profile information were saved successfully.</p>';
102 adminlog("Profile updated for user ".$user->name.".", MTS_USER, MTA_UPDATE);
103 } else {
104 $userid = (int) $_GET['edit'];
105 $user = get_userdatabyid( $userid );
106 }
107
108 if( !$user ) $error.='<p>The specified user does not exist.</p>';
109
110 adminhead('Edit User Profile');
111 adminmenu('users.php');
112
113 if( $user ) {
114
115 ?>
116 <form enctype="multipart/form-data" name="profile" id="your-profile" action="user-edit.php" method="post">
117 <input type="hidden" name="edit" value="<?php echo $userid; ?>" />
118 <h2>Editing "<?php echo htmlentities($user->name); ?>"</h2>
119 <p>Modify details for this contributer.</p>
120
121 <fieldset>
122 <legend>Name</legend>
123 <p><label>Username:<br />
124 <input type="text" name="user_login" value="<?php echo htmlentities($user->name); ?>" disabled="disabled" /></label></p>
125
126 <p><label>Nickname:<br />
127 <input type="text" name="nickname" value="<?php echo htmlentities($user->nameplate); ?>" /></label></p>
128
129 <p><label>Email:<br />
130 <input type="text" name="email" value="<?php echo htmlentities($user->email); ?>" /></label></p>
131
132 </fieldset>
133
134 <fieldset>
135 <legend>Rant Defaults</legend>
136 <p><label>Link<br />
137 <input type="text" name="rant-link" value="<?php echo htmlentities($user->default_link); ?>" /></label></p>
138
139 <p><label>Upload New Image<br />
140 <input type="hidden" name="MAX_FILE_SIZE" value="10000000" />
141 <input name="rant_image" type="file" /></label></p>
142
143 <?php
144 $rantimage_filename = SITE_RANT.'/' . $user->default_image;
145 if( !file_exists( SITE_PATH_ABS.'/' . $rantimage_filename )) {
146 echo '<p>There is currently no default rant image for this contributor.</p>';
147 } else {
148 echo '<p><img src="' . SITE_HOST . '/' . SITE_PATH . '/' . $rantimage_filename . '" width="150" /></p>';
149 }
150 ?>
151
152 </fieldset>
153
154 <fieldset>
155 <legend>Change Password</legend>
156 <p><label>Old Password</br/>
157 <input type="password" name="password_old" value="" /></label></p>
158
159 <p><label>New Password</br/>
160 <input type="password" name="password_new1" value="" /></label></p>
161
162 <p><label>Confirm New Password</br/>
163 <input type="password" name="password_new2" value="" /></label></p>
164 </fieldset>
165
166
167 <br clear="all" />
168
169 <p class="submit"><input type="submit" value="Update Profile &raquo;" name="submit" /></p>
170
171 </form>
172 </div>
173
174 <?php
175
176 }
177
178 adminfooter();
179 ?>
@@ -0,0 +1,70
1 <?php
2
3 /* This page displays a list of comics, 15 per page. */
4
5 require_once('include/admin.inc.php');
6
7 auth_redirect(); // Require logged in user to access this page.
8
9 adminhead('Users');
10 adminmenu();
11 ?>
12 <h2>User Administration</h2>
13 <p>Make changes to accounts for contributers to the website.</p>
14
15 <?php
16
17 $users = $mtdb->getAll("SELECT id,name,email,nameplate FROM contributor");
18
19 ?>
20
21 <table class="widefat">
22 <thead>
23 <tr>
24 <th scope="col" style="text-align: center;">User #</th>
25 <th scope="col">Username</th>
26 <th scope="col">Nickname</th>
27 <th scope="col">Email</th>
28 <th scope="col"></th>
29 </tr>
30 </thead>
31
32 <tbody id="the-list">
33 <?php
34 $alternate=false;
35 foreach( $users as $s ) {
36 $alternate=!$alternate;
37 ?>
38 <tr id="comic-<?php echo $s->id; ?>" <?php if($alternate) echo 'class="alternate"'; ?>>
39 <th scope="row" style="text-align: center;"><?php echo $s->id; ?></th>
40 <td><?php echo $s->name; ?></td>
41 <td><?php echo $s->nameplate; ?></td>
42 <td><?php echo $s->email; ?></td>
43 <td style="text-align: center;"><a href="user-edit.php?edit=<?php echo $s->id; ?>">Edit</a></td>
44 </tr>
45 <?php
46 }
47 ?>
48 </tbody>
49 </table>
50
51
52 <form enctype="multipart/form-data" name="create-user" id="create-user" action="user-edit.php" method="post">
53 <input type="hidden" name="edit" value="NEW" />
54
55 <h2>Create New Contributor</h2>
56 <div class="narrow">
57 <table class="editform" width="100% cellspacing="2" cellpadding="5">
58 <tr>
59 <th scope="row" width="33%">Username</th>
60 <td width="66%"><input name="user_login" type="text" id="user_login" value="" /></th>
61 </tr>
62 </table>
63
64 <p class="submit"><input type="submit" value="Create &raquo;" name="submit" /></p>
65 </div>
66 </form>
67
68 <?php
69 adminfooter();
70 ?>
@@ -0,0 +1,65
1 <?php
2
3 /* This page displays a list of comics, 15 per page. */
4
5 require_once('include/admin.inc.php');
6
7 auth_redirect(); // Require logged in user to access this page.
8
9 adminhead('Admin Log');
10 adminmenu();
11 ?>
12 <h2>Admin Log</h2>
13
14 <?php
15
16 $page = 1;
17 if( isset($_GET['page'] )) $page = (int) $_GET['page'];
18
19 $perpage = 15;
20 $start = ($page-1) * $perpage;
21
22 $total = ceil( $mtdb->getOne("SELECT COUNT(*) FROM admin_log") / $perpage );
23 $entries = $mtdb->getAll("SELECT UNIX_TIMESTAMP(l.logdate) AS logstamp, l.logdate AS logdate, c.name AS cname, c.email AS cmail, s.name AS section, action, level, message FROM admin_log l JOIN admin_section s ON l.section = s.id LEFT JOIN contributor c ON l.contributor = c.id ORDER BY l.logdate DESC LIMIT $start,$perpage");
24
25 pagination( $page, $total );
26
27 ?>
28
29 <table class="widefat">
30 <thead>
31 <tr>
32 <th scope="col" style="text-align: center;">Date</th>
33 <th scope="col">Contributor</th>
34 <th scope="col">Section</th>
35 <th scope="col">Action</th>
36 <th scope="col">Level</th>
37 <th scope="col">Message</th>
38 </tr>
39 </thead>
40
41 <tbody id="the-list">
42 <?php
43 $alternate=false;
44 foreach( $entries as $e ) {
45 $alternate=!$alternate;
46 ?>
47 <tr id="log-<?php echo $e->logstamp; ?>" <?php if($alternate) echo 'class="alternate"'; ?>>
48 <th scope="row" style="text-align: center;"><?php echo $e->logdate; ?></th>
49 <td><?php echo $e->cname; ?></td>
50 <td><?php echo $e->section; ?></td>
51 <td><?php echo $e->action; ?></td>
52 <td><?php echo $e->level ?></td>
53 <td><?php echo $e->message; ?></td>
54 </tr>
55 <?php
56 }
57 ?>
58 </tbody>
59 </table>
60
61
62
63 <?php
64 adminfooter();
65 ?>
This diff has been collapsed as it changes many lines, (1341 lines changed) Show them Hide them
@@ -0,0 +1,1341
1 * html #poststuff {
2 height: 100%; /* kill peekaboo bug in IE */
3 }
4
5 /* This is the Holly Hack \*/
6 * html .wrap { height: 1% }
7 /* For Win IE's eyes only */
8
9 body {
10 border: none;
11 }
12 a {
13 border-bottom: 1px solid #69c;
14 color: #00019b;
15 text-decoration: none;
16 }
17
18 a.delete:hover {
19 background: #c00;
20 color: #fff;
21 }
22
23 #devnews h4 {
24 font-family: Georgia, "Times New Roman", Times, serif;
25 font-size: 18px;
26 font-weight: normal;
27 }
28
29 #planetnews ul {
30 list-style: none;
31 margin: 0;
32 padding: 0;
33 }
34
35 #planetnews li {
36 width: 17%;
37 margin: 1%;
38 float: left;
39 }
40
41 #planetnews li a {
42 display: block;
43 padding: .5em;
44 background: #ddd;
45 height: 6em;
46 overflow: hidden;
47 }
48
49 #planetnews cite {
50 font-size: 11px;
51 }
52
53 #planetnews li .post {
54 font-family: Georgia, "Times New Roman", Times, serif;
55 font-size: 18px;
56 display: block;
57 height: 60px;
58 overflow: hidden;
59 }
60
61 #planetnews .hidden {
62 display: none;
63 }
64
65 .readmore {
66 clear: both;
67 text-align: right;
68 margin-right: 5em;
69 }
70
71 .widefat {
72 width: 100%;
73 }
74
75 .widefat td, .widefat th {
76 padding: 5px 6px;
77 }
78
79 .widefat th {
80 text-align: left;
81 }
82
83 .plugins p {
84 margin: 4px;
85 padding: 0;
86 }
87
88 .plugins .name {
89 font-size: 16px;
90 }
91
92 .import-system {
93 font-size: 16px;
94 }
95
96 thead, .thead {
97 background: #dfdfdf
98 }
99
100 #import-upload-form {
101 margin: auto;
102 background: #eee;
103 padding: 1em;
104 }
105
106 a.edit, a.delete, a.edit:hover, a.delete:hover {
107 border-bottom: none;
108 display: block;
109 padding: 5px 0;
110 text-align: center;
111 }
112
113 a.edit:hover {
114 background: #ccc;
115 color: #036;
116 }
117
118 a:visited {
119 color: #006;
120 }
121
122 a:hover {
123 /* border-bottom: 1px solid #3a75ae;*/
124 color: #069;
125 }
126
127 body {
128 background: #f9fcfe;
129 color: #000;
130 margin: 0;
131 padding: 0;
132 }
133
134 body, td {
135 font: 13px "Lucida Grande", "Lucida Sans Unicode", Tahoma, Verdana;
136 }
137
138 fieldset {
139 border: none;
140 padding: 3px;
141 }
142
143 fieldset label.selectit {
144 display: block;
145 font-size: 11px;
146 padding: 0 2px;
147 }
148
149 fieldset label.selectit:hover {
150 background: #e9e9e9;
151 }
152
153 fieldset legend {
154 padding: .1em .3em;
155 }
156
157 fieldset.options {
158 padding: 1em;
159 }
160
161 fieldset.options legend {
162 font-size: 1.5em;
163 font-weight: bold;
164 font-family: Georgia, "Times New Roman", Times, serif;
165 }
166
167 form, label input {
168 margin: 0;
169 padding: 0;
170 }
171
172 h2 {
173 border-bottom: .5em solid #e5f3ff;
174 color: #333;
175 font: normal 32px/5px serif;
176 margin: 5px 10px;
177 }
178
179 img, #footer a {
180 border: 0;
181 }
182
183 input:focus, textarea:focus, label:focus {
184 background: #fff;
185 border: 1px solid #686868;
186 }
187
188 label {
189 cursor: pointer;
190 }
191
192 li, dd {
193 margin-bottom: 6px;
194 }
195
196 p, li, dl, dd, dt {
197 line-height: 140%;
198 }
199
200 textarea, input, select {
201 background: #f4f4f4;
202 border: 1px solid #b2b2b2;
203 color: #000;
204 font: 13px Verdana, Arial, Helvetica, sans-serif;
205 margin: 1px;
206 padding: 3px;
207 }
208
209 #uploading {
210 border-style: none;
211 padding: 0px;
212 margin-bottom: 16px;
213 height: 18em;
214 width: 100%;
215 }
216
217 form#upload th {
218 text-align: right;
219 }
220
221 form#upload #post_content, form#upload #post_title {
222 width: 250px;
223 }
224
225 form#upload #post_content {
226 height: 50px;
227 }
228
229 .attpreview {
230 width: 1px; /* hug */
231 text-align: center;
232 }
233
234 .alignleft {
235 float: left
236 }
237
238 .alignright {
239 float: right;
240 }
241
242 .alternate {
243 background: #d1d1d1;
244 }
245
246 .anchors {
247 margin: 10px 20px 10px 20px;
248 }
249
250 .available-theme {
251 width: 30%;
252 margin: 0 1em;
253 float: left;
254 text-align: center;
255 height: 28em;
256 overflow: hidden;
257 }
258
259 .available-theme a.screenshot {
260 width: 250px;
261 height: 200px;
262 display: block;
263 margin: auto;
264 background: #f1f1f1;
265 border: 1px solid #ccc;
266 margin-bottom: 10px;
267 overflow: hidden;
268 }
269
270 .available-theme a.screenshot:hover {
271 /* border: 1px solid #666;*/
272 }
273
274 .available-theme img {
275 width: 100%;
276 }
277
278 .checkbox {
279 background: #fff;
280 border: none;
281 margin: 0;
282 padding: 0;
283 }
284
285 .code {
286 font-family: "Courier New", Courier, monospace;
287 }
288
289 .commentlist li {
290 border-bottom: 1px solid #ccc;
291 padding: 1em 1em .2em;
292 margin: 0;
293 }
294
295 .commentlist p {
296 padding: 0;
297 margin: 0 0 .8em;
298 }
299
300 .clear {
301 clear: both;
302 height: 2px;
303 }
304
305 .hidden {
306 display: none;
307 }
308
309 .navigation {
310 display: block;
311 text-align: center;
312 margin-top: 10px;
313 margin-bottom: 30px;
314 }
315
316 .post-categories {
317 display: inline;
318 margin: 0;
319 padding: 0;
320 }
321
322 .post-categories li, #ed_toolbar {
323 display: inline;
324 }
325
326 .quicktags, .search {
327 background: #ccc;
328 color: #000;
329 font: 12px Georgia, "Times New Roman", Times, serif;
330 }
331
332 .submit input, .submit input:focus, .button, .button:focus {
333 background: url( images/fade-butt.png );
334 border: 3px double #999;
335 border-left-color: #ccc;
336 border-top-color: #ccc;
337 color: #333;
338 padding: 0.25em;
339 }
340
341 .submit input:active, .button:active {
342 background: #f4f4f4;
343 border: 3px double #ccc;
344 border-left-color: #999;
345 border-top-color: #999;
346 }
347
348 .button, .button:focus {
349 padding: 0.15em;
350 }
351
352 * html .button {
353 padding: 0;
354 }
355
356 .submit, .editform th, #postcustomsubmit {
357 text-align: right;
358 }
359
360 .optiontable {
361 width: 100%;
362 }
363
364 .optiontable td, .optiontable th {
365 padding: .5em;
366 }
367
368 .optiontable th {
369 width: 33%;
370 text-align: right;
371 font-size: 1.3em;
372 font-weight: normal;
373 }
374
375 .unapproved {
376 color: #888;
377 }
378
379 .unapproved a:link {
380 color: #b9bcff;
381 }
382
383 .unapproved a:visited {
384 color: #696dff;
385 }
386
387 .unapproved a:hover {
388 color: #009ef0;
389 }
390
391 .approve {
392 display: none;
393 }
394
395 .unapproved .approve {
396 display: inline;
397 }
398
399 .unapproved .unapprove {
400 display: none;
401 }
402
403 .updated, .confirm {
404 background: #CFEBF7 url(images/notice.gif) no-repeat 1em;
405 border: 1px solid #2580B2;
406 margin: 1em 5% 10px;
407 padding: 0 1em 0 3em;
408 }
409
410 .error {
411 background: #FFEFF7;
412 border: 1px solid #c69;
413 margin: 1em 5% 10px;
414 padding: 0 1em 0 1em;
415 }
416
417 .wrap {
418 background: #fff;
419 border: 1px solid #ccc;
420 clear: both;
421 margin: 15px 5%;
422 padding: 1em;
423 }
424
425 .narrow {
426 width: 450px;
427 margin: auto;
428 }
429
430 .narrow p {
431 line-height: 150%;
432 }
433
434 .wrap h2 {
435 margin: .4em 0 .5em;
436 clear: both;
437 }
438
439 * html .wrap h2 {
440 margin-top: 1em;
441 }
442
443 table .vers {
444 text-align: center;
445 }
446
447 textarea.all-options, input.all-options {
448 width: 250px;
449 }
450
451 input.disabled, textarea.disabled {
452 background: #ccc;
453 }
454
455 #adminmenu {
456 background: #83B4D8;
457 border-top: 3px solid #448abd;
458 margin: 0;
459 padding: .2em .2em .3em 2em;
460 }
461
462
463 #adminmenu .current, #submenu .current {
464 font-weight: bold;
465 text-decoration: none;
466 }
467
468 #adminmenu a {
469 color: #000;
470 font-size: 14px;
471 font-weight: normal;
472 margin: 0;
473 padding: 3px 5px;
474 border-bottom: none;
475 }
476
477 #adminmenu a:hover, #adminmenu a.current {
478 background: #ddeaf4;
479 color: #333;
480 }
481
482 #adminmenu li, #submenu li {
483 display: inline;
484 line-height: 200%;
485 list-style: none;
486 text-align: center;
487 }
488
489 #adminmenu a.current {
490 background: #0d324f;
491 border-right: 2px solid #4f96c8;
492 border-top: 1px solid #96c0de;
493 color: #fff;
494 padding-bottom: 8px;
495 }
496
497 #submenu, #minisub {
498 background: #0d324f;
499 border-bottom: none;
500 margin: 0;
501 padding: 3px 2em 0 3em;
502 }
503
504 #minisub {
505 height: 6px;
506 }
507
508 #submenu .current {
509 background: #f9fcfe;
510 border-top: 1px solid #045290;
511 border-right: 2px solid #045290;
512 color: #000;
513 }
514
515 #submenu a {
516 border: none;
517 color: #fff;
518 font-size: 12px;
519 padding: .3em .4em .4em;
520 }
521
522 #submenu a:hover {
523 background: #ddeaf4;
524 color: #393939;
525 }
526
527 #submenu li {
528 line-height: 180%;
529 height: 25px;
530 }
531
532
533 #categorydiv input, #poststatusdiv input, #commentstatusdiv input, #pingstatusdiv input {
534 border: none;
535 }
536
537 #postdiv, #titlediv, #guiddiv, #linkdiv {
538 margin: 0 8px 0 0;
539 padding: 0px;
540 }
541
542 #postdivrich {
543 margin: 0px;
544 padding: 0px;
545 }
546
547 #content {
548 margin: 0 0 0 0;
549 width: 95%;
550 }
551
552 #postdivrich #content {
553 padding: .7em;
554 line-height: 140%;
555 }
556
557 #titlediv input, #guiddiv input, #linkdiv input {
558 margin: 0px;
559 width: 100%;
560 }
561
562 #currenttheme img {
563 float: left;
564 border: 1px solid #666;
565 margin-right: 1em;
566 margin-bottom: 1.5em;
567 width: 300px;
568 }
569
570 input.delete:hover {
571 background: #ce0000;
572 color: #fff;
573 }
574
575 #deletebookmarks:hover {
576 background: #ce0000;
577 color: #fff;
578 }
579
580 #postdivrich #quicktags {
581 background: #f0f0ee;
582 padding: 0px;
583 border: 1px solid #ccc;
584 border-bottom: none;
585 }
586
587 #postdiv #quicktags {
588 padding-right: 6px;
589 }
590
591 #postdivrich #quicktags {
592 display: none;
593 }
594
595 #quicktags #ed_toolbar {
596 padding: 0px 2px;
597 }
598
599 #ed_toolbar input {
600 background: #fff url( images/fade-butt.png ) repeat-x 0px -2px;
601 margin: 3px 2px 2px;
602 }
603
604 #quicktags #ed_strong {
605 font-weight: bold;
606 }
607
608 #quicktags #ed_link {
609 color: blue;
610 text-decoration: underline;
611 }
612
613 #quicktags #ed_del {
614 text-decoration: line-through;
615 }
616
617 #quicktags #ed_em {
618 font-style: italic;
619 }
620
621 #quicktags #ed_code {
622 font-family: "Courier New", Courier, mono;
623 margin-bottom: 3px;
624 }
625
626 #title {
627 font-size: 1.7em;
628 padding: 4px;
629 }
630
631 #postexcerpt div, #attachmentlinks div {
632 margin-right: 8px;
633 }
634
635 #attachmentlinks textarea {
636 width: 100%;
637 height: 2.5em;
638 margin-bottom: 6px;
639 }
640
641 * html #postexcerpt .dbx-toggle-open, * html #postexcerpt .dbx-toggle-open {
642 padding-right: 8px;
643 }
644
645 #excerpt, .attachmentlinks {
646 margin: 0px;
647 height: 4em;
648 width: 100%;
649 }
650
651 #footer {
652 clear: both;
653 text-align: center;
654 width: 500px;
655 margin: auto;
656 height: 100px;
657 }
658
659 #footer .docs {
660 padding-top: 19px;
661 line-height: 160%;
662 }
663
664 #footer .docs a {
665 text-decoration: underline;
666 }
667 #footer .logo {
668 float: left;
669 margin: 0;
670 padding: 0;
671 font-size:0.5em;
672 }
673
674 #login {
675 position: relative;
676 background: url('images/login-bkg-tile.gif') no-repeat top center;
677 color: #fff;
678 margin: 5em auto 1em;
679 padding: 20px 0 0;
680 width: 425px;
681 }
682
683 #login form {
684 background: url('images/login-bkg-bottom.gif') no-repeat bottom center;
685 padding: 0 50px 25px;
686 }
687
688 #login #login_error {
689 background: #0e3350;
690 border: 1px solid #2571ab;
691 color: #ebcd4e;
692 font-size: 11px;
693 font-weight: bold;
694 padding: .6em;
695 width: 310px;
696 margin: 0 auto;
697 text-align: center;
698 }
699
700 #login p {
701 font-size: 12px;
702 }
703
704 #login p.message {
705 width: 310px;
706 margin: 0 auto 1em;
707 }
708
709 #login #login_error a {
710 color: #ebcd4e;
711 border-color: #ebcd4e;
712 }
713
714 #login #send {
715 color: #fff;
716 text-align: left;
717 font-weight: normal;
718 font-size: 1.1em;
719 _width: 325px;
720 _margin: 0 auto 15px;
721 }
722
723 #login h1 a {
724 margin: 0 auto;
725 height: 88px;
726 width: 320px;
727 display: block;
728 border-bottom: none;
729 text-indent: -9999px;
730 }
731
732 #login .hide {
733 display: none;
734 }
735
736 #login .message {
737 font-size: 10pt;
738 text-align: center;
739 }
740
741 #login .register {
742 font-size: 20px;
743 }
744
745 #login input {
746 padding: 4px;
747 }
748
749 .login ul, #protected #login .bottom {
750 list-style: none;
751 width: 325px;
752 margin: 0 auto;
753 padding: 0;
754 line-height: 1.2;
755 }
756
757 .login ul li {
758 font-size: 11px;
759 }
760
761 .login ul li a {
762 color: #0d324f;
763 border: none;
764 }
765
766 #login ul li a:hover {
767 color: #fff;
768 }
769
770 #login .input {
771 font-size: 1.8em;
772 margin-top: 3px;
773 width: 97%;
774 }
775
776 #login p label {
777 font-size: 11px;
778 }
779
780 #login input#rememberme {
781 background-color: 0e3757;
782 }
783
784 #login #submit {
785 margin: 0;
786 font-size: 15px;
787 }
788
789 .plugins p {
790 }
791
792 #login .fullwidth {
793 width: 320px;
794 }
795
796 #searchform {
797 float: left;
798 margin-right: 1em;
799 width: 18em;
800 }
801
802 #viewarc {
803 float: left;
804 width: 23em;
805 margin-bottom: 1em;
806 }
807
808 #viewcat {
809 float: left;
810 width: 30em;
811 margin-bottom: 1em;
812 }
813
814 #postcustom .updatemeta, #postcustom .deletemeta {
815 margin: auto;
816 }
817
818 #postcustom table {
819 border: 1px solid #ccc;
820 margin: 0px;
821 width: 100%;
822 }
823
824 #postcustom table input, #postcustom table textarea {
825 width: 95%;
826 }
827
828 #poststuff {
829 margin-right: 16em;
830 }
831
832 #save {
833 width: 15em;
834 }
835
836 #template div {
837 margin-right: 190px;
838 }
839
840 * html #template div {
841 margin-right: 0px;
842 }
843
844 #template, #template div, #editcat, #addcat {
845 zoom: 1;
846 }
847
848 #template textarea {
849 font: small 'Courier New', Courier, monospace;
850 width: 97%;
851 }
852
853 #templateside {
854 float: right;
855 width: 170px;
856 overflow: hidden;
857 }
858
859 #templateside h3, #postcustom p.submit {
860 margin: 0;
861 }
862
863 #templateside ol, #templateside ul {
864 list-style: none;
865 margin: .5em;
866 padding: 0;
867 }
868
869 #user_info {
870 position: absolute;
871 right: 1em;
872 top: 0;
873 color: #fff;
874 font-size: .9em;
875 }
876
877 #user_info a {
878 color: #fff;
879 }
880
881 #wphead {
882 background: #14568a;
883 padding: .8em 19em .8em 2em;
884 color: #c3def1;
885 }
886
887 #wphead a {
888 color: #fff;
889 }
890
891 #wphead h1 {
892 font-size: 2.5em;
893 font-weight: normal;
894 letter-spacing: -.05em;
895 margin: 0;
896 font-family: Georgia, "Times New Roman", Times, serif
897 }
898
899 #wphead h1 span {
900 font-size: .4em;
901 letter-spacing: 0;
902 }
903
904 #zeitgeist {
905 background: #eee;
906 border: 1px solid #c5c5c5;
907 float: right;
908 font-size: 90%;
909 margin-bottom: .5em;
910 margin-left: 1em;
911 margin-top: .5em;
912 padding: 1em;
913 width: 40%;
914 }
915
916 #zeitgeist h2, fieldset legend a {
917 border-bottom: none;
918 }
919
920 * html #zeitgeist h2 {
921 padding-top: 10px;
922 }
923
924 #zeitgeist h2 {
925 margin-top: .4em;
926 }
927
928 #zeitgeist h3 {
929 border-bottom: 1px solid #ccc;
930 font-size: 16px;
931 margin: 1em 0 0;
932 }
933
934 #zeitgeist h3 cite {
935 font-size: 12px;
936 font-style: normal;
937 }
938
939 #zeitgeist li, #zeitgeist p {
940 margin: .2em 0;
941 }
942
943 #zeitgeist ul {
944 margin: 0 0 .3em .6em;
945 padding: 0 0 0 .6em;
946 }
947
948 .active td {
949 background: #BEB;
950 }
951 .active .name {
952 background: #9C9;
953 }
954 .alternate.active td {
955 background: #ADA;
956 }
957 .alternate.active .name {
958 background: #8B8;
959 }
960
961 #namediv, #emaildiv, #uridiv {
962 float: left;
963 }
964
965 #ajax-response {
966 padding: .5em;
967 }
968
969 /* A handy div class for hiding controls.
970 Some browsers will disable them when you
971 set display:none; */
972 .zerosize {
973 height: 0px;
974 width: 0px;
975 margin: 0px;
976 border: 0px;
977 padding: 0px;
978 overflow: hidden;
979 position: absolute;
980 }
981
982 /* Box stuff */
983 .dbx-clone {
984 position:absolute;
985 visibility:hidden;
986 }
987 .dbx-clone, .dbx-clone .dbx-handle-cursor {
988 cursor:move !important;
989 }
990 .dbx-dummy {
991 display:block;
992 width:0;
993 height:0;
994 overflow:hidden;
995 }
996 .dbx-group, .dbx-box, .dbx-handle {
997 position:relative;
998 display:block;
999 }
1000
1001 #grabit {
1002 width: 188px;
1003 }
1004
1005 * html #themeselect {
1006 padding: 0px 3px;
1007 height: 22px;
1008 }
1009
1010 /****************************************************************
1011 avoid padding, margins or borders on dbx-box,
1012 to reduce visual discrepancies between it and the clone.
1013 overall, dbx-box is best left as visually unstyled as possible
1014 *****************************************************************/
1015 .dbx-box {
1016 margin:0;
1017 padding:0;
1018 border:none;
1019 }
1020
1021 /* Can change this */
1022 #moremeta fieldset, #advancedstuff fieldset {
1023 margin-bottom: 0.3em;
1024 }
1025 #moremeta fieldset div {
1026 margin: 2px 0 0 0px;
1027 padding: 7px;
1028 }
1029 #moremeta {
1030 line-height: 100%;
1031 margin-right: 15px;
1032 position: absolute;
1033 right: 5%;
1034 width: 14.5em;
1035 }
1036 #moremeta select {
1037 width: 96%;
1038 }
1039
1040 #slugdiv input, #passworddiv input, #authordiv select, #thumbdiv input, #parentdiv input {
1041 margin-top: .5em;
1042 width: 90%;
1043 }
1044
1045 #moremeta h3, #advancedstuff h3 {
1046 padding: 3px;
1047 font-weight: normal;
1048 font-size: 13px;
1049 }
1050
1051 #advancedstuff div {
1052 margin-top: .5em;
1053 }
1054
1055 #categorydiv ul {
1056 list-style: none;
1057 padding: 0;
1058 margin-left: 10px;
1059 }
1060
1061 #categorychecklist {
1062 height: 12em;
1063 overflow: auto;
1064 margin-top: 8px;
1065 }
1066
1067 #categorychecklist li {
1068 margin: 0;
1069 padding: 0;
1070 }
1071
1072 #ajaxcat input {
1073 border: 1px solid #ccc;
1074 }
1075
1076 #your-profile #rich_editing {
1077 border: none;
1078 background: #fff;
1079 }
1080
1081 #your-profile fieldset {
1082 border: 1px solid #ccc;
1083 float: left;
1084 width: 40%;
1085 padding: .5em 2em 1em;
1086 margin: 1em 1em 1em 0;
1087 }
1088
1089 #your-profile fieldset input {
1090 width: 100%;
1091 font-size: 20px;
1092 padding: 2px;
1093 }
1094
1095 #your-profile fieldset textarea {
1096 width: 100%;
1097 padding: 2px;
1098 }
1099
1100 #your-profile legend {
1101 font-family: Georgia, "Times New Roman", Times, serif;
1102 font-size: 22px;
1103 }
1104
1105 /* default box styles */
1106
1107 /* toggle state of inner content area */
1108 .dbx-box-open .dbx-content {
1109 display: block;
1110 }
1111 .dbx-box-closed .dbx-content {
1112 display: none;
1113 }
1114
1115 #moremeta .dbx-content {
1116 background: url(images/box-butt.gif) no-repeat bottom right;
1117 padding-bottom: 10px;
1118 padding-right: 2px;
1119 }
1120
1121 #moremeta fieldset.dbx-box-closed {
1122 background: url(images/box-butt.gif) no-repeat bottom;
1123 padding-bottom: 9px;
1124 }
1125
1126 /* handles */
1127
1128 .dbx-handle {
1129 background: #2685af;
1130 padding: 6px 1em 2px;
1131 font-size: 12px;
1132 margin: 0;
1133 color: #E3EFF5;
1134 }
1135
1136 #moremeta .dbx-handle {
1137 padding: 6px 1em 2px;
1138 font-size: 12px;
1139 background: #2685af url(images/box-head.gif) no-repeat right;
1140 }
1141
1142 #moremeta .dbx-box {
1143 background: url(images/box-bg.gif) repeat-y right;
1144 }
1145
1146 #advancedstuff h3.dbx-handle {
1147 margin-left: 7px;
1148 margin-bottom: -7px;
1149 padding: 6px 1em 0 3px;
1150 height: 19px;
1151 font-size: 12px;
1152 background: #2685af url(images/box-head-right.gif) no-repeat top right;
1153 }
1154
1155 #advancedstuff div.dbx-handle-wrapper {
1156 margin: 0 0 0 -7px;
1157 background: #fff url(images/box-head-left.gif) no-repeat top left;
1158 }
1159
1160 #advancedstuff div.dbx-content {
1161 margin-left: 8px;
1162 background: url(images/box-bg-right.gif) repeat-y right;
1163 padding: 10px 10px 15px 0px;
1164 }
1165
1166 #postexcerpt div.dbx-content {
1167 margin-right: 0;
1168 padding-right: 17px;
1169 }
1170
1171 #advancedstuff div.dbx-content-wrapper {
1172 margin-left: -7px;
1173 margin-right: 0;
1174 background: url(images/box-bg-left.gif) repeat-y left;
1175 }
1176
1177 #advancedstuff fieldset.dbx-box {
1178 padding-bottom: 9px;
1179 margin-left: 6px;
1180 background: url(images/box-butt-right.gif) no-repeat bottom right;
1181 }
1182
1183 #advancedstuff div.dbx-box-wrapper {
1184 background: url(images/box-butt-left.gif) no-repeat bottom left;
1185 }
1186
1187 #advancedstuff .dbx-box-closed div.dbx-content-wrapper {
1188 padding-bottom: 2px;
1189 background: url(images/box-butt-left.gif) no-repeat bottom left;
1190 }
1191
1192 #advancedstuff .dbx-box {
1193 background: url(images/box-butt-right.gif) no-repeat bottom right;
1194 }
1195
1196
1197 /* handle cursors */
1198 .dbx-handle-cursor {
1199 cursor: move;
1200 }
1201
1202 /* toggle images */
1203 a.dbx-toggle, a.dbx-toggle:visited {
1204 display:block;
1205 overflow: hidden;
1206 background-image: url( images/toggle.gif );
1207 position: absolute;
1208 top: 0px;
1209 right: 0px;
1210 background-repeat: no-repeat;
1211 border: 0px;
1212 margin: 0px;
1213 padding: 0px;
1214 }
1215
1216 #moremeta a.dbx-toggle, #moremeta a.dbx-toggle-open:visited {
1217 height: 25px;
1218 width: 27px;
1219 background-position: 0 0px;
1220 }
1221
1222 #moremeta a.dbx-toggle-open, #moremeta a.dbx-toggle-open:visited {
1223 height: 25px;
1224 width: 27px;
1225 background-position: 0 -25px;
1226 }
1227
1228 #advancedstuff a.dbx-toggle, #advancedstuff a.dbx-toggle-open:visited {
1229 height: 22px;
1230 width: 22px;
1231 top: 3px;
1232 right: 5px;
1233 background-position: 0 -3px;
1234 }
1235
1236 #advancedstuff a.dbx-toggle-open, #advancedstuff a.dbx-toggle-open:visited {
1237 height: 22px;
1238 width: 22px;
1239 top: 3px;
1240 right: 5px;
1241 background-position: 0 -28px;
1242 }
1243
1244 #categorychecklist {
1245 margin-right: 6px;
1246 }
1247
1248 /* additional clone styles */
1249 .dbx-clone {
1250 opacity: 0.8;
1251 -moz-opacity: 0.8;
1252 -khtml-opacity: 0.8;
1253 filter: alpha(opacity=80);
1254 }
1255
1256 #newcat {
1257 width: 120px;
1258 margin-right: 5px;
1259 }
1260
1261 input #catadd {
1262 background: #a4a4a4;
1263 border-bottom: 1px solid #898989;
1264 border-left: 1px solid #bcbcbc;
1265 border-right: 1px solid #898989;
1266 border-top: 1px solid #bcbcbc;
1267 color: #fff;
1268 font-size: 10px;
1269 padding: 0;
1270 margin: 0;
1271 font-weight: bold;
1272 height: 20px;
1273 margin-bottom: 2px;
1274 text-align: center;
1275 width: 37px;
1276 }
1277
1278 #howto {
1279 font-size: 11px;
1280 margin: 0 5px;
1281 display: block;
1282 }
1283
1284 #jaxcat {
1285 margin: 0;
1286 padding: 0;
1287 }
1288
1289 #ajax-response.alignleft {
1290 margin-left: 2em;
1291 }
1292
1293 #postdivrich #edButtons {
1294 padding-left: 3px;
1295 }
1296
1297 #postdivrich #content, #postdivrich #content:active {
1298 border: 1px solid #ccc;
1299 }
1300
1301 #edButtons input, #edButtons input:active {
1302 margin: 0px 2px -1px;
1303 }
1304
1305 #edButtons input.edButtonFore, #edButtons input.edButtonFore:active {
1306 background: #f0f0ee;
1307 border-bottom: 1px solid #f0f0ee;
1308 }
1309
1310 #edButtons input.edButtonBack, #edButtons input.edButtonBack:active {
1311 background: #fff url( images/fade-butt.png ) repeat-x 0px 15px;
1312 border-bottom: 1px solid #ccc;
1313 }
1314
1315 .page-numbers {
1316 padding: 4px 7px;
1317 border: 1px solid #fff;
1318 margin-right: 3px;
1319 }
1320
1321 a.page-numbers {
1322 border: 1px solid #ccc;
1323 }
1324
1325 a.page-numbers:hover {
1326 border: 1px solid #999;
1327 }
1328
1329 .page-numbers.current {
1330 border: 1px solid #999;
1331 font-weight: bold;
1332 }
1333
1334 .pagenav span {
1335 font-weight: bold;
1336 margin: 0 6px;
1337 }
1338
1339 ul.historic {
1340 margin-bottom: 1em;
1341 } No newline at end of file
Comments 0
You need to be logged in to leave comments. Login now