Index: trunk/phase3/includes/specials/SpecialRevisiondelete.php |
— | — | @@ -598,1414 +598,3 @@ |
599 | 599 | } |
600 | 600 | } |
601 | 601 | |
602 | | -/** |
603 | | - * Temporary b/c interface, collection of static functions. |
604 | | - * @ingroup SpecialPage |
605 | | - */ |
606 | | -class RevisionDeleter { |
607 | | - /** |
608 | | - * Checks for a change in the bitfield for a certain option and updates the |
609 | | - * provided array accordingly. |
610 | | - * |
611 | | - * @param $desc String: description to add to the array if the option was |
612 | | - * enabled / disabled. |
613 | | - * @param $field Integer: the bitmask describing the single option. |
614 | | - * @param $diff Integer: the xor of the old and new bitfields. |
615 | | - * @param $new Integer: the new bitfield |
616 | | - * @param $arr Array: the array to update. |
617 | | - */ |
618 | | - protected static function checkItem( $desc, $field, $diff, $new, &$arr ) { |
619 | | - if( $diff & $field ) { |
620 | | - $arr[ ( $new & $field ) ? 0 : 1 ][] = $desc; |
621 | | - } |
622 | | - } |
623 | | - |
624 | | - /** |
625 | | - * Gets an array of message keys describing the changes made to the visibility |
626 | | - * of the revision. If the resulting array is $arr, then $arr[0] will contain an |
627 | | - * array of strings describing the items that were hidden, $arr[2] will contain |
628 | | - * an array of strings describing the items that were unhidden, and $arr[3] will |
629 | | - * contain an array with a single string, which can be one of "applied |
630 | | - * restrictions to sysops", "removed restrictions from sysops", or null. |
631 | | - * |
632 | | - * @param $n Integer: the new bitfield. |
633 | | - * @param $o Integer: the old bitfield. |
634 | | - * @return An array as described above. |
635 | | - */ |
636 | | - protected static function getChanges( $n, $o ) { |
637 | | - $diff = $n ^ $o; |
638 | | - $ret = array( 0 => array(), 1 => array(), 2 => array() ); |
639 | | - // Build bitfield changes in language |
640 | | - self::checkItem( 'revdelete-content', |
641 | | - Revision::DELETED_TEXT, $diff, $n, $ret ); |
642 | | - self::checkItem( 'revdelete-summary', |
643 | | - Revision::DELETED_COMMENT, $diff, $n, $ret ); |
644 | | - self::checkItem( 'revdelete-uname', |
645 | | - Revision::DELETED_USER, $diff, $n, $ret ); |
646 | | - // Restriction application to sysops |
647 | | - if( $diff & Revision::DELETED_RESTRICTED ) { |
648 | | - if( $n & Revision::DELETED_RESTRICTED ) |
649 | | - $ret[2][] = 'revdelete-restricted'; |
650 | | - else |
651 | | - $ret[2][] = 'revdelete-unrestricted'; |
652 | | - } |
653 | | - return $ret; |
654 | | - } |
655 | | - |
656 | | - /** |
657 | | - * Gets a log message to describe the given revision visibility change. This |
658 | | - * message will be of the form "[hid {content, edit summary, username}]; |
659 | | - * [unhid {...}][applied restrictions to sysops] for $count revisions: $comment". |
660 | | - * |
661 | | - * @param $count Integer: The number of effected revisions. |
662 | | - * @param $nbitfield Integer: The new bitfield for the revision. |
663 | | - * @param $obitfield Integer: The old bitfield for the revision. |
664 | | - * @param $isForLog Boolean |
665 | | - * @param $forContent Boolean |
666 | | - */ |
667 | | - public static function getLogMessage( $count, $nbitfield, $obitfield, $isForLog = false, $forContent = false ) { |
668 | | - global $wgLang, $wgContLang; |
669 | | - |
670 | | - $lang = $forContent ? $wgContLang : $wgLang; |
671 | | - $msgFunc = $forContent ? "wfMsgForContent" : "wfMsg"; |
672 | | - |
673 | | - $s = ''; |
674 | | - $changes = self::getChanges( $nbitfield, $obitfield ); |
675 | | - array_walk($changes, 'RevisionDeleter::expandMessageArray', $forContent); |
676 | | - |
677 | | - $changesText = array(); |
678 | | - |
679 | | - if( count( $changes[0] ) ) { |
680 | | - $changesText[] = $msgFunc( 'revdelete-hid', $lang->commaList( $changes[0] ) ); |
681 | | - } |
682 | | - if( count( $changes[1] ) ) { |
683 | | - $changesText[] = $msgFunc( 'revdelete-unhid', $lang->commaList( $changes[1] ) ); |
684 | | - } |
685 | | - |
686 | | - $s = $lang->semicolonList( $changesText ); |
687 | | - if( count( $changes[2] ) ) { |
688 | | - $s .= $s ? ' (' . $changes[2][0] . ')' : ' ' . $changes[2][0]; |
689 | | - } |
690 | | - |
691 | | - $msg = $isForLog ? 'logdelete-log-message' : 'revdelete-log-message'; |
692 | | - return wfMsgExt( $msg, $forContent ? array( 'parsemag', 'content' ) : array( 'parsemag' ), $s, $lang->formatNum($count) ); |
693 | | - } |
694 | | - |
695 | | - private static function expandMessageArray(& $msg, $key, $forContent) { |
696 | | - if ( is_array ($msg) ) { |
697 | | - array_walk($msg, 'RevisionDeleter::expandMessageArray', $forContent); |
698 | | - } else { |
699 | | - if ( $forContent ) { |
700 | | - $msg = wfMsgForContent($msg); |
701 | | - } else { |
702 | | - $msg = wfMsg($msg); |
703 | | - } |
704 | | - } |
705 | | - } |
706 | | - |
707 | | - // Get DB field name for URL param... |
708 | | - // Future code for other things may also track |
709 | | - // other types of revision-specific changes. |
710 | | - // @returns string One of log_id/rev_id/fa_id/ar_timestamp/oi_archive_name |
711 | | - public static function getRelationType( $typeName ) { |
712 | | - if ( isset( SpecialRevisionDelete::$deprecatedTypeMap[$typeName] ) ) { |
713 | | - $typeName = SpecialRevisionDelete::$deprecatedTypeMap[$typeName]; |
714 | | - } |
715 | | - if ( isset( SpecialRevisionDelete::$allowedTypes[$typeName] ) ) { |
716 | | - $class = SpecialRevisionDelete::$allowedTypes[$typeName]['list-class']; |
717 | | - $list = new $class( null, null, null ); |
718 | | - return $list->getIdField(); |
719 | | - } else { |
720 | | - return null; |
721 | | - } |
722 | | - } |
723 | | - |
724 | | - // Checks if a revision still exists in the revision table. |
725 | | - // If it doesn't, returns the corresponding ar_timestamp field |
726 | | - // so that this key can be used instead. |
727 | | - public static function checkRevisionExistence( $title, $revid ) { |
728 | | - $dbr = wfGetDB( DB_SLAVE ); |
729 | | - $exists = $dbr->selectField( 'revision', '1', |
730 | | - array( 'rev_id' => $revid ), __METHOD__ ); |
731 | | - |
732 | | - if ( $exists ) { |
733 | | - return true; |
734 | | - } |
735 | | - |
736 | | - $timestamp = $dbr->selectField( 'archive', 'ar_timestamp', |
737 | | - array( 'ar_namespace' => $title->getNamespace(), |
738 | | - 'ar_title' => $title->getDBkey(), |
739 | | - 'ar_rev_id' => $revid ), __METHOD__ ); |
740 | | - |
741 | | - return $timestamp; |
742 | | - } |
743 | | - |
744 | | - // Creates utility links for log entries. |
745 | | - public static function getLogLinks( $title, $paramArray, $skin, $messages ) { |
746 | | - global $wgLang; |
747 | | - |
748 | | - if( count($paramArray) >= 2 ) { |
749 | | - // Different revision types use different URL params... |
750 | | - $originalKey = $key = $paramArray[0]; |
751 | | - // $paramArray[1] is a CSV of the IDs |
752 | | - $Ids = explode( ',', $paramArray[1] ); |
753 | | - $query = $paramArray[1]; |
754 | | - $revert = array(); |
755 | | - |
756 | | - // For if undeleted revisions are found amidst deleted ones. |
757 | | - $undeletedRevisions = array(); |
758 | | - |
759 | | - // This is not going to work if some revs are deleted and some |
760 | | - // aren't. |
761 | | - if ($key == 'revision') { |
762 | | - foreach( $Ids as $k => $id ) { |
763 | | - $existResult = |
764 | | - self::checkRevisionExistence( $title, $id ); |
765 | | - |
766 | | - if ($existResult !== true) { |
767 | | - $key = 'archive'; |
768 | | - $Ids[$k] = $existResult; |
769 | | - } else { |
770 | | - // Undeleted revision amidst deleted ones |
771 | | - unset($Ids[$k]); |
772 | | - $undeletedRevisions[] = $id; |
773 | | - } |
774 | | - } |
775 | | - |
776 | | - if ( $key == $originalKey ) { |
777 | | - $Ids = $undeletedRevisions; |
778 | | - $undeletedRevisions = array(); |
779 | | - } |
780 | | - } |
781 | | - |
782 | | - // Diff link for single rev deletions |
783 | | - if( count($Ids) == 1 && !count($undeletedRevisions) ) { |
784 | | - // Live revision diffs... |
785 | | - if( in_array( $key, array( 'oldid', 'revision' ) ) ) { |
786 | | - $revert[] = $skin->link( |
787 | | - $title, |
788 | | - $messages['diff'], |
789 | | - array(), |
790 | | - array( |
791 | | - 'diff' => intval( $Ids[0] ), |
792 | | - 'unhide' => 1 |
793 | | - ), |
794 | | - array( 'known', 'noclasses' ) |
795 | | - ); |
796 | | - // Deleted revision diffs... |
797 | | - } else if( in_array( $key, array( 'artimestamp','archive' ) ) ) { |
798 | | - $revert[] = $skin->link( |
799 | | - SpecialPage::getTitleFor( 'Undelete' ), |
800 | | - $messages['diff'], |
801 | | - array(), |
802 | | - array( |
803 | | - 'target' => $title->getPrefixedDBKey(), |
804 | | - 'diff' => 'prev', |
805 | | - 'timestamp' => $Ids[0] |
806 | | - ), |
807 | | - array( 'known', 'noclasses' ) |
808 | | - ); |
809 | | - } |
810 | | - } |
811 | | - |
812 | | - // View/modify link... |
813 | | - if ( count($undeletedRevisions) ) { |
814 | | - // FIXME THIS IS A HORRIBLE HORRIBLE HACK AND SHOULD DIE |
815 | | - // It's not possible to pass a list of both deleted and |
816 | | - // undeleted revisions to SpecialRevisionDelete, so we're |
817 | | - // stuck with two links. See bug 23363. |
818 | | - $restoreLinks = array(); |
819 | | - |
820 | | - $restoreLinks[] = $skin->link( |
821 | | - SpecialPage::getTitleFor( 'Revisiondelete' ), |
822 | | - $messages['revdel-restore-visible'], |
823 | | - array(), |
824 | | - array( |
825 | | - 'target' => $title->getPrefixedText(), |
826 | | - 'type' => $originalKey, |
827 | | - 'ids' => implode(',', $undeletedRevisions), |
828 | | - ), |
829 | | - array( 'known', 'noclasses' ) |
830 | | - ); |
831 | | - |
832 | | - $restoreLinks[] = $skin->link( |
833 | | - SpecialPage::getTitleFor( 'Revisiondelete' ), |
834 | | - $messages['revdel-restore-deleted'], |
835 | | - array(), |
836 | | - array( |
837 | | - 'target' => $title->getPrefixedText(), |
838 | | - 'type' => $key, |
839 | | - 'ids' => implode(',', $Ids), |
840 | | - ), |
841 | | - array( 'known', 'noclasses' ) |
842 | | - ); |
843 | | - |
844 | | - $revert[] = $messages['revdel-restore'] . ' [' . |
845 | | - $wgLang->pipeList( $restoreLinks ) . ']'; |
846 | | - } else { |
847 | | - $revert[] = $skin->link( |
848 | | - SpecialPage::getTitleFor( 'Revisiondelete' ), |
849 | | - $messages['revdel-restore'], |
850 | | - array(), |
851 | | - array( |
852 | | - 'target' => $title->getPrefixedText(), |
853 | | - 'type' => $key, |
854 | | - 'ids' => implode(',', $Ids), |
855 | | - ), |
856 | | - array( 'known', 'noclasses' ) |
857 | | - ); |
858 | | - } |
859 | | - |
860 | | - // Pipe links |
861 | | - $revert = wfMsg( 'parentheses', $wgLang->pipeList( $revert ) ); |
862 | | - } |
863 | | - return $revert; |
864 | | - } |
865 | | -} |
866 | | - |
867 | | -/** |
868 | | - * Abstract base class for a list of deletable items |
869 | | - */ |
870 | | -abstract class RevDel_List { |
871 | | - var $special, $title, $ids, $res, $current; |
872 | | - var $type = null; // override this |
873 | | - var $idField = null; // override this |
874 | | - var $dateField = false; // override this |
875 | | - var $authorIdField = false; // override this |
876 | | - var $authorNameField = false; // override this |
877 | | - |
878 | | - /** |
879 | | - * @param $special The parent SpecialPage |
880 | | - * @param $title The target title |
881 | | - * @param $ids Array of IDs |
882 | | - */ |
883 | | - public function __construct( $special, $title, $ids ) { |
884 | | - $this->special = $special; |
885 | | - $this->title = $title; |
886 | | - $this->ids = $ids; |
887 | | - } |
888 | | - |
889 | | - /** |
890 | | - * Get the internal type name of this list. Equal to the table name. |
891 | | - */ |
892 | | - public function getType() { |
893 | | - return $this->type; |
894 | | - } |
895 | | - |
896 | | - /** |
897 | | - * Get the DB field name associated with the ID list |
898 | | - */ |
899 | | - public function getIdField() { |
900 | | - return $this->idField; |
901 | | - } |
902 | | - |
903 | | - /** |
904 | | - * Get the DB field name storing timestamps |
905 | | - */ |
906 | | - public function getTimestampField() { |
907 | | - return $this->dateField; |
908 | | - } |
909 | | - |
910 | | - /** |
911 | | - * Get the DB field name storing user ids |
912 | | - */ |
913 | | - public function getAuthorIdField() { |
914 | | - return $this->authorIdField; |
915 | | - } |
916 | | - |
917 | | - /** |
918 | | - * Get the DB field name storing user names |
919 | | - */ |
920 | | - public function getAuthorNameField() { |
921 | | - return $this->authorNameField; |
922 | | - } |
923 | | - /** |
924 | | - * Set the visibility for the revisions in this list. Logging and |
925 | | - * transactions are done here. |
926 | | - * |
927 | | - * @param $params Associative array of parameters. Members are: |
928 | | - * value: The integer value to set the visibility to |
929 | | - * comment: The log comment. |
930 | | - * @return Status |
931 | | - */ |
932 | | - public function setVisibility( $params ) { |
933 | | - $bitPars = $params['value']; |
934 | | - $comment = $params['comment']; |
935 | | - |
936 | | - $this->res = false; |
937 | | - $dbw = wfGetDB( DB_MASTER ); |
938 | | - $this->doQuery( $dbw ); |
939 | | - $dbw->begin(); |
940 | | - $status = Status::newGood(); |
941 | | - $missing = array_flip( $this->ids ); |
942 | | - $this->clearFileOps(); |
943 | | - $idsForLog = array(); |
944 | | - $authorIds = $authorIPs = array(); |
945 | | - |
946 | | - for ( $this->reset(); $this->current(); $this->next() ) { |
947 | | - $item = $this->current(); |
948 | | - unset( $missing[ $item->getId() ] ); |
949 | | - |
950 | | - $oldBits = $item->getBits(); |
951 | | - // Build the actual new rev_deleted bitfield |
952 | | - $newBits = SpecialRevisionDelete::extractBitfield( $bitPars, $oldBits ); |
953 | | - |
954 | | - if ( $oldBits == $newBits ) { |
955 | | - $status->warning( 'revdelete-no-change', $item->formatDate(), $item->formatTime() ); |
956 | | - $status->failCount++; |
957 | | - continue; |
958 | | - } elseif ( $oldBits == 0 && $newBits != 0 ) { |
959 | | - $opType = 'hide'; |
960 | | - } elseif ( $oldBits != 0 && $newBits == 0 ) { |
961 | | - $opType = 'show'; |
962 | | - } else { |
963 | | - $opType = 'modify'; |
964 | | - } |
965 | | - |
966 | | - if ( $item->isHideCurrentOp( $newBits ) ) { |
967 | | - // Cannot hide current version text |
968 | | - $status->error( 'revdelete-hide-current', $item->formatDate(), $item->formatTime() ); |
969 | | - $status->failCount++; |
970 | | - continue; |
971 | | - } |
972 | | - if ( !$item->canView() ) { |
973 | | - // Cannot access this revision |
974 | | - $msg = ($opType == 'show') ? |
975 | | - 'revdelete-show-no-access' : 'revdelete-modify-no-access'; |
976 | | - $status->error( $msg, $item->formatDate(), $item->formatTime() ); |
977 | | - $status->failCount++; |
978 | | - continue; |
979 | | - } |
980 | | - // Cannot just "hide from Sysops" without hiding any fields |
981 | | - if( $newBits == Revision::DELETED_RESTRICTED ) { |
982 | | - $status->warning( 'revdelete-only-restricted', $item->formatDate(), $item->formatTime() ); |
983 | | - $status->failCount++; |
984 | | - continue; |
985 | | - } |
986 | | - |
987 | | - // Update the revision |
988 | | - $ok = $item->setBits( $newBits ); |
989 | | - |
990 | | - if ( $ok ) { |
991 | | - $idsForLog[] = $item->getId(); |
992 | | - $status->successCount++; |
993 | | - if( $item->getAuthorId() > 0 ) { |
994 | | - $authorIds[] = $item->getAuthorId(); |
995 | | - } else if( IP::isIPAddress( $item->getAuthorName() ) ) { |
996 | | - $authorIPs[] = $item->getAuthorName(); |
997 | | - } |
998 | | - } else { |
999 | | - $status->error( 'revdelete-concurrent-change', $item->formatDate(), $item->formatTime() ); |
1000 | | - $status->failCount++; |
1001 | | - } |
1002 | | - } |
1003 | | - |
1004 | | - // Handle missing revisions |
1005 | | - foreach ( $missing as $id => $unused ) { |
1006 | | - $status->error( 'revdelete-modify-missing', $id ); |
1007 | | - $status->failCount++; |
1008 | | - } |
1009 | | - |
1010 | | - if ( $status->successCount == 0 ) { |
1011 | | - $status->ok = false; |
1012 | | - $dbw->rollback(); |
1013 | | - return $status; |
1014 | | - } |
1015 | | - |
1016 | | - // Save success count |
1017 | | - $successCount = $status->successCount; |
1018 | | - |
1019 | | - // Move files, if there are any |
1020 | | - $status->merge( $this->doPreCommitUpdates() ); |
1021 | | - if ( !$status->isOK() ) { |
1022 | | - // Fatal error, such as no configured archive directory |
1023 | | - $dbw->rollback(); |
1024 | | - return $status; |
1025 | | - } |
1026 | | - |
1027 | | - // Log it |
1028 | | - $this->updateLog( array( |
1029 | | - 'title' => $this->title, |
1030 | | - 'count' => $successCount, |
1031 | | - 'newBits' => $newBits, |
1032 | | - 'oldBits' => $oldBits, |
1033 | | - 'comment' => $comment, |
1034 | | - 'ids' => $idsForLog, |
1035 | | - 'authorIds' => $authorIds, |
1036 | | - 'authorIPs' => $authorIPs |
1037 | | - ) ); |
1038 | | - $dbw->commit(); |
1039 | | - |
1040 | | - // Clear caches |
1041 | | - $status->merge( $this->doPostCommitUpdates() ); |
1042 | | - return $status; |
1043 | | - } |
1044 | | - |
1045 | | - /** |
1046 | | - * Reload the list data from the master DB. This can be done after setVisibility() |
1047 | | - * to allow $item->getHTML() to show the new data. |
1048 | | - */ |
1049 | | - function reloadFromMaster() { |
1050 | | - $dbw = wfGetDB( DB_MASTER ); |
1051 | | - $this->res = $this->doQuery( $dbw ); |
1052 | | - } |
1053 | | - |
1054 | | - /** |
1055 | | - * Record a log entry on the action |
1056 | | - * @param $params Associative array of parameters: |
1057 | | - * newBits: The new value of the *_deleted bitfield |
1058 | | - * oldBits: The old value of the *_deleted bitfield. |
1059 | | - * title: The target title |
1060 | | - * ids: The ID list |
1061 | | - * comment: The log comment |
1062 | | - * authorsIds: The array of the user IDs of the offenders |
1063 | | - * authorsIPs: The array of the IP/anon user offenders |
1064 | | - */ |
1065 | | - protected function updateLog( $params ) { |
1066 | | - // Get the URL param's corresponding DB field |
1067 | | - $field = RevisionDeleter::getRelationType( $this->getType() ); |
1068 | | - if( !$field ) { |
1069 | | - throw new MWException( "Bad log URL param type!" ); |
1070 | | - } |
1071 | | - // Put things hidden from sysops in the oversight log |
1072 | | - if ( ( $params['newBits'] | $params['oldBits'] ) & $this->getSuppressBit() ) { |
1073 | | - $logType = 'suppress'; |
1074 | | - } else { |
1075 | | - $logType = 'delete'; |
1076 | | - } |
1077 | | - // Add params for effected page and ids |
1078 | | - $logParams = $this->getLogParams( $params ); |
1079 | | - // Actually add the deletion log entry |
1080 | | - $log = new LogPage( $logType ); |
1081 | | - $logid = $log->addEntry( $this->getLogAction(), $params['title'], |
1082 | | - $params['comment'], $logParams ); |
1083 | | - // Allow for easy searching of deletion log items for revision/log items |
1084 | | - $log->addRelations( $field, $params['ids'], $logid ); |
1085 | | - $log->addRelations( 'target_author_id', $params['authorIds'], $logid ); |
1086 | | - $log->addRelations( 'target_author_ip', $params['authorIPs'], $logid ); |
1087 | | - } |
1088 | | - |
1089 | | - /** |
1090 | | - * Get the log action for this list type |
1091 | | - */ |
1092 | | - public function getLogAction() { |
1093 | | - return 'revision'; |
1094 | | - } |
1095 | | - |
1096 | | - /** |
1097 | | - * Get log parameter array. |
1098 | | - * @param $params Associative array of log parameters, same as updateLog() |
1099 | | - * @return array |
1100 | | - */ |
1101 | | - public function getLogParams( $params ) { |
1102 | | - return array( |
1103 | | - $this->getType(), |
1104 | | - implode( ',', $params['ids'] ), |
1105 | | - "ofield={$params['oldBits']}", |
1106 | | - "nfield={$params['newBits']}" |
1107 | | - ); |
1108 | | - } |
1109 | | - |
1110 | | - /** |
1111 | | - * Initialise the current iteration pointer |
1112 | | - */ |
1113 | | - protected function initCurrent() { |
1114 | | - $row = $this->res->current(); |
1115 | | - if ( $row ) { |
1116 | | - $this->current = $this->newItem( $row ); |
1117 | | - } else { |
1118 | | - $this->current = false; |
1119 | | - } |
1120 | | - } |
1121 | | - |
1122 | | - /** |
1123 | | - * Start iteration. This must be called before current() or next(). |
1124 | | - * @return First list item |
1125 | | - */ |
1126 | | - public function reset() { |
1127 | | - if ( !$this->res ) { |
1128 | | - $this->res = $this->doQuery( wfGetDB( DB_SLAVE ) ); |
1129 | | - } else { |
1130 | | - $this->res->rewind(); |
1131 | | - } |
1132 | | - $this->initCurrent(); |
1133 | | - return $this->current; |
1134 | | - } |
1135 | | - |
1136 | | - /** |
1137 | | - * Get the current list item, or false if we are at the end |
1138 | | - */ |
1139 | | - public function current() { |
1140 | | - return $this->current; |
1141 | | - } |
1142 | | - |
1143 | | - /** |
1144 | | - * Move the iteration pointer to the next list item, and return it. |
1145 | | - */ |
1146 | | - public function next() { |
1147 | | - $this->res->next(); |
1148 | | - $this->initCurrent(); |
1149 | | - return $this->current; |
1150 | | - } |
1151 | | - |
1152 | | - /** |
1153 | | - * Get the number of items in the list. |
1154 | | - */ |
1155 | | - public function length() { |
1156 | | - if( !$this->res ) { |
1157 | | - return 0; |
1158 | | - } else { |
1159 | | - return $this->res->numRows(); |
1160 | | - } |
1161 | | - } |
1162 | | - |
1163 | | - /** |
1164 | | - * Clear any data structures needed for doPreCommitUpdates() and doPostCommitUpdates() |
1165 | | - * STUB |
1166 | | - */ |
1167 | | - public function clearFileOps() { |
1168 | | - } |
1169 | | - |
1170 | | - /** |
1171 | | - * A hook for setVisibility(): do batch updates pre-commit. |
1172 | | - * STUB |
1173 | | - * @return Status |
1174 | | - */ |
1175 | | - public function doPreCommitUpdates() { |
1176 | | - return Status::newGood(); |
1177 | | - } |
1178 | | - |
1179 | | - /** |
1180 | | - * A hook for setVisibility(): do any necessary updates post-commit. |
1181 | | - * STUB |
1182 | | - * @return Status |
1183 | | - */ |
1184 | | - public function doPostCommitUpdates() { |
1185 | | - return Status::newGood(); |
1186 | | - } |
1187 | | - |
1188 | | - /** |
1189 | | - * Create an item object from a DB result row |
1190 | | - * @param $row stdclass |
1191 | | - */ |
1192 | | - abstract public function newItem( $row ); |
1193 | | - |
1194 | | - /** |
1195 | | - * Do the DB query to iterate through the objects. |
1196 | | - * @param $db Database object to use for the query |
1197 | | - */ |
1198 | | - abstract public function doQuery( $db ); |
1199 | | - |
1200 | | - /** |
1201 | | - * Get the integer value of the flag used for suppression |
1202 | | - */ |
1203 | | - abstract public function getSuppressBit(); |
1204 | | -} |
1205 | | - |
1206 | | -/** |
1207 | | - * Abstract base class for deletable items |
1208 | | - */ |
1209 | | -abstract class RevDel_Item { |
1210 | | - /** The parent SpecialPage */ |
1211 | | - var $special; |
1212 | | - |
1213 | | - /** The parent RevDel_List */ |
1214 | | - var $list; |
1215 | | - |
1216 | | - /** The DB result row */ |
1217 | | - var $row; |
1218 | | - |
1219 | | - /** |
1220 | | - * @param $list RevDel_List |
1221 | | - * @param $row DB result row |
1222 | | - */ |
1223 | | - public function __construct( $list, $row ) { |
1224 | | - $this->special = $list->special; |
1225 | | - $this->list = $list; |
1226 | | - $this->row = $row; |
1227 | | - } |
1228 | | - |
1229 | | - /** |
1230 | | - * Get the ID, as it would appear in the ids URL parameter |
1231 | | - */ |
1232 | | - public function getId() { |
1233 | | - $field = $this->list->getIdField(); |
1234 | | - return $this->row->$field; |
1235 | | - } |
1236 | | - |
1237 | | - /** |
1238 | | - * Get the date, formatted with $wgLang |
1239 | | - */ |
1240 | | - public function formatDate() { |
1241 | | - global $wgLang; |
1242 | | - return $wgLang->date( $this->getTimestamp() ); |
1243 | | - } |
1244 | | - |
1245 | | - /** |
1246 | | - * Get the time, formatted with $wgLang |
1247 | | - */ |
1248 | | - public function formatTime() { |
1249 | | - global $wgLang; |
1250 | | - return $wgLang->time( $this->getTimestamp() ); |
1251 | | - } |
1252 | | - |
1253 | | - /** |
1254 | | - * Get the timestamp in MW 14-char form |
1255 | | - */ |
1256 | | - public function getTimestamp() { |
1257 | | - $field = $this->list->getTimestampField(); |
1258 | | - return wfTimestamp( TS_MW, $this->row->$field ); |
1259 | | - } |
1260 | | - |
1261 | | - /** |
1262 | | - * Get the author user ID |
1263 | | - */ |
1264 | | - public function getAuthorId() { |
1265 | | - $field = $this->list->getAuthorIdField(); |
1266 | | - return intval( $this->row->$field ); |
1267 | | - } |
1268 | | - |
1269 | | - /** |
1270 | | - * Get the author user name |
1271 | | - */ |
1272 | | - public function getAuthorName() { |
1273 | | - $field = $this->list->getAuthorNameField(); |
1274 | | - return strval( $this->row->$field ); |
1275 | | - } |
1276 | | - |
1277 | | - /** |
1278 | | - * Returns true if the item is "current", and the operation to set the given |
1279 | | - * bits can't be executed for that reason |
1280 | | - * STUB |
1281 | | - */ |
1282 | | - public function isHideCurrentOp( $newBits ) { |
1283 | | - return false; |
1284 | | - } |
1285 | | - |
1286 | | - /** |
1287 | | - * Returns true if the current user can view the item |
1288 | | - */ |
1289 | | - abstract public function canView(); |
1290 | | - |
1291 | | - /** |
1292 | | - * Returns true if the current user can view the item text/file |
1293 | | - */ |
1294 | | - abstract public function canViewContent(); |
1295 | | - |
1296 | | - /** |
1297 | | - * Get the current deletion bitfield value |
1298 | | - */ |
1299 | | - abstract public function getBits(); |
1300 | | - |
1301 | | - /** |
1302 | | - * Get the HTML of the list item. Should be include <li></li> tags. |
1303 | | - * This is used to show the list in HTML form, by the special page. |
1304 | | - */ |
1305 | | - abstract public function getHTML(); |
1306 | | - |
1307 | | - /** |
1308 | | - * Set the visibility of the item. This should do any necessary DB queries. |
1309 | | - * |
1310 | | - * The DB update query should have a condition which forces it to only update |
1311 | | - * if the value in the DB matches the value fetched earlier with the SELECT. |
1312 | | - * If the update fails because it did not match, the function should return |
1313 | | - * false. This prevents concurrency problems. |
1314 | | - * |
1315 | | - * @return boolean success |
1316 | | - */ |
1317 | | - abstract public function setBits( $newBits ); |
1318 | | -} |
1319 | | - |
1320 | | -/** |
1321 | | - * List for revision table items |
1322 | | - */ |
1323 | | -class RevDel_RevisionList extends RevDel_List { |
1324 | | - var $currentRevId; |
1325 | | - var $type = 'revision'; |
1326 | | - var $idField = 'rev_id'; |
1327 | | - var $dateField = 'rev_timestamp'; |
1328 | | - var $authorIdField = 'rev_user'; |
1329 | | - var $authorNameField = 'rev_user_text'; |
1330 | | - |
1331 | | - public function doQuery( $db ) { |
1332 | | - $ids = array_map( 'intval', $this->ids ); |
1333 | | - return $db->select( array('revision','page'), '*', |
1334 | | - array( |
1335 | | - 'rev_page' => $this->title->getArticleID(), |
1336 | | - 'rev_id' => $ids, |
1337 | | - 'rev_page = page_id' |
1338 | | - ), |
1339 | | - __METHOD__, |
1340 | | - array( 'ORDER BY' => 'rev_id DESC' ) |
1341 | | - ); |
1342 | | - } |
1343 | | - |
1344 | | - public function newItem( $row ) { |
1345 | | - return new RevDel_RevisionItem( $this, $row ); |
1346 | | - } |
1347 | | - |
1348 | | - public function getCurrent() { |
1349 | | - if ( is_null( $this->currentRevId ) ) { |
1350 | | - $dbw = wfGetDB( DB_MASTER ); |
1351 | | - $this->currentRevId = $dbw->selectField( |
1352 | | - 'page', 'page_latest', $this->title->pageCond(), __METHOD__ ); |
1353 | | - } |
1354 | | - return $this->currentRevId; |
1355 | | - } |
1356 | | - |
1357 | | - public function getSuppressBit() { |
1358 | | - return Revision::DELETED_RESTRICTED; |
1359 | | - } |
1360 | | - |
1361 | | - public function doPreCommitUpdates() { |
1362 | | - $this->title->invalidateCache(); |
1363 | | - return Status::newGood(); |
1364 | | - } |
1365 | | - |
1366 | | - public function doPostCommitUpdates() { |
1367 | | - $this->title->purgeSquid(); |
1368 | | - // Extensions that require referencing previous revisions may need this |
1369 | | - wfRunHooks( 'ArticleRevisionVisiblitySet', array( &$this->title ) ); |
1370 | | - return Status::newGood(); |
1371 | | - } |
1372 | | -} |
1373 | | - |
1374 | | -/** |
1375 | | - * Item class for a revision table row |
1376 | | - */ |
1377 | | -class RevDel_RevisionItem extends RevDel_Item { |
1378 | | - var $revision; |
1379 | | - |
1380 | | - public function __construct( $list, $row ) { |
1381 | | - parent::__construct( $list, $row ); |
1382 | | - $this->revision = new Revision( $row ); |
1383 | | - } |
1384 | | - |
1385 | | - public function canView() { |
1386 | | - return $this->revision->userCan( Revision::DELETED_RESTRICTED ); |
1387 | | - } |
1388 | | - |
1389 | | - public function canViewContent() { |
1390 | | - return $this->revision->userCan( Revision::DELETED_TEXT ); |
1391 | | - } |
1392 | | - |
1393 | | - public function getBits() { |
1394 | | - return $this->revision->mDeleted; |
1395 | | - } |
1396 | | - |
1397 | | - public function setBits( $bits ) { |
1398 | | - $dbw = wfGetDB( DB_MASTER ); |
1399 | | - // Update revision table |
1400 | | - $dbw->update( 'revision', |
1401 | | - array( 'rev_deleted' => $bits ), |
1402 | | - array( |
1403 | | - 'rev_id' => $this->revision->getId(), |
1404 | | - 'rev_page' => $this->revision->getPage(), |
1405 | | - 'rev_deleted' => $this->getBits() |
1406 | | - ), |
1407 | | - __METHOD__ |
1408 | | - ); |
1409 | | - if ( !$dbw->affectedRows() ) { |
1410 | | - // Concurrent fail! |
1411 | | - return false; |
1412 | | - } |
1413 | | - // Update recentchanges table |
1414 | | - $dbw->update( 'recentchanges', |
1415 | | - array( |
1416 | | - 'rc_deleted' => $bits, |
1417 | | - 'rc_patrolled' => 1 |
1418 | | - ), |
1419 | | - array( |
1420 | | - 'rc_this_oldid' => $this->revision->getId(), // condition |
1421 | | - // non-unique timestamp index |
1422 | | - 'rc_timestamp' => $dbw->timestamp( $this->revision->getTimestamp() ), |
1423 | | - ), |
1424 | | - __METHOD__ |
1425 | | - ); |
1426 | | - return true; |
1427 | | - } |
1428 | | - |
1429 | | - public function isDeleted() { |
1430 | | - return $this->revision->isDeleted( Revision::DELETED_TEXT ); |
1431 | | - } |
1432 | | - |
1433 | | - public function isHideCurrentOp( $newBits ) { |
1434 | | - return ( $newBits & Revision::DELETED_TEXT ) |
1435 | | - && $this->list->getCurrent() == $this->getId(); |
1436 | | - } |
1437 | | - |
1438 | | - /** |
1439 | | - * Get the HTML link to the revision text. |
1440 | | - * Overridden by RevDel_ArchiveItem. |
1441 | | - */ |
1442 | | - protected function getRevisionLink() { |
1443 | | - global $wgLang; |
1444 | | - $date = $wgLang->timeanddate( $this->revision->getTimestamp(), true ); |
1445 | | - if ( $this->isDeleted() && !$this->canViewContent() ) { |
1446 | | - return $date; |
1447 | | - } |
1448 | | - return $this->special->skin->link( |
1449 | | - $this->list->title, |
1450 | | - $date, |
1451 | | - array(), |
1452 | | - array( |
1453 | | - 'oldid' => $this->revision->getId(), |
1454 | | - 'unhide' => 1 |
1455 | | - ) |
1456 | | - ); |
1457 | | - } |
1458 | | - |
1459 | | - /** |
1460 | | - * Get the HTML link to the diff. |
1461 | | - * Overridden by RevDel_ArchiveItem |
1462 | | - */ |
1463 | | - protected function getDiffLink() { |
1464 | | - if ( $this->isDeleted() && !$this->canViewContent() ) { |
1465 | | - return wfMsgHtml('diff'); |
1466 | | - } else { |
1467 | | - return |
1468 | | - $this->special->skin->link( |
1469 | | - $this->list->title, |
1470 | | - wfMsgHtml('diff'), |
1471 | | - array(), |
1472 | | - array( |
1473 | | - 'diff' => $this->revision->getId(), |
1474 | | - 'oldid' => 'prev', |
1475 | | - 'unhide' => 1 |
1476 | | - ), |
1477 | | - array( |
1478 | | - 'known', |
1479 | | - 'noclasses' |
1480 | | - ) |
1481 | | - ); |
1482 | | - } |
1483 | | - } |
1484 | | - |
1485 | | - public function getHTML() { |
1486 | | - $difflink = $this->getDiffLink(); |
1487 | | - $revlink = $this->getRevisionLink(); |
1488 | | - $userlink = $this->special->skin->revUserLink( $this->revision ); |
1489 | | - $comment = $this->special->skin->revComment( $this->revision ); |
1490 | | - if ( $this->isDeleted() ) { |
1491 | | - $revlink = "<span class=\"history-deleted\">$revlink</span>"; |
1492 | | - } |
1493 | | - return "<li>($difflink) $revlink $userlink $comment</li>"; |
1494 | | - } |
1495 | | -} |
1496 | | - |
1497 | | -/** |
1498 | | - * List for archive table items, i.e. revisions deleted via action=delete |
1499 | | - */ |
1500 | | -class RevDel_ArchiveList extends RevDel_RevisionList { |
1501 | | - var $type = 'archive'; |
1502 | | - var $idField = 'ar_timestamp'; |
1503 | | - var $dateField = 'ar_timestamp'; |
1504 | | - var $authorIdField = 'ar_user'; |
1505 | | - var $authorNameField = 'ar_user_text'; |
1506 | | - |
1507 | | - public function doQuery( $db ) { |
1508 | | - $timestamps = array(); |
1509 | | - foreach ( $this->ids as $id ) { |
1510 | | - $timestamps[] = $db->timestamp( $id ); |
1511 | | - } |
1512 | | - return $db->select( 'archive', '*', |
1513 | | - array( |
1514 | | - 'ar_namespace' => $this->title->getNamespace(), |
1515 | | - 'ar_title' => $this->title->getDBkey(), |
1516 | | - 'ar_timestamp' => $timestamps |
1517 | | - ), |
1518 | | - __METHOD__, |
1519 | | - array( 'ORDER BY' => 'ar_timestamp DESC' ) |
1520 | | - ); |
1521 | | - } |
1522 | | - |
1523 | | - public function newItem( $row ) { |
1524 | | - return new RevDel_ArchiveItem( $this, $row ); |
1525 | | - } |
1526 | | - |
1527 | | - public function doPreCommitUpdates() { |
1528 | | - return Status::newGood(); |
1529 | | - } |
1530 | | - |
1531 | | - public function doPostCommitUpdates() { |
1532 | | - return Status::newGood(); |
1533 | | - } |
1534 | | -} |
1535 | | - |
1536 | | -/** |
1537 | | - * Item class for a archive table row |
1538 | | - */ |
1539 | | -class RevDel_ArchiveItem extends RevDel_RevisionItem { |
1540 | | - public function __construct( $list, $row ) { |
1541 | | - RevDel_Item::__construct( $list, $row ); |
1542 | | - $this->revision = Revision::newFromArchiveRow( $row, |
1543 | | - array( 'page' => $this->list->title->getArticleId() ) ); |
1544 | | - } |
1545 | | - |
1546 | | - public function getId() { |
1547 | | - # Convert DB timestamp to MW timestamp |
1548 | | - return $this->revision->getTimestamp(); |
1549 | | - } |
1550 | | - |
1551 | | - public function setBits( $bits ) { |
1552 | | - $dbw = wfGetDB( DB_MASTER ); |
1553 | | - $dbw->update( 'archive', |
1554 | | - array( 'ar_deleted' => $bits ), |
1555 | | - array( 'ar_namespace' => $this->list->title->getNamespace(), |
1556 | | - 'ar_title' => $this->list->title->getDBkey(), |
1557 | | - // use timestamp for index |
1558 | | - 'ar_timestamp' => $this->row->ar_timestamp, |
1559 | | - 'ar_rev_id' => $this->row->ar_rev_id, |
1560 | | - 'ar_deleted' => $this->getBits() |
1561 | | - ), |
1562 | | - __METHOD__ ); |
1563 | | - return (bool)$dbw->affectedRows(); |
1564 | | - } |
1565 | | - |
1566 | | - protected function getRevisionLink() { |
1567 | | - global $wgLang; |
1568 | | - $undelete = SpecialPage::getTitleFor( 'Undelete' ); |
1569 | | - $date = $wgLang->timeanddate( $this->revision->getTimestamp(), true ); |
1570 | | - if ( $this->isDeleted() && !$this->canViewContent() ) { |
1571 | | - return $date; |
1572 | | - } |
1573 | | - return $this->special->skin->link( $undelete, $date, array(), |
1574 | | - array( |
1575 | | - 'target' => $this->list->title->getPrefixedText(), |
1576 | | - 'timestamp' => $this->revision->getTimestamp() |
1577 | | - ) ); |
1578 | | - } |
1579 | | - |
1580 | | - protected function getDiffLink() { |
1581 | | - if ( $this->isDeleted() && !$this->canViewContent() ) { |
1582 | | - return wfMsgHtml( 'diff' ); |
1583 | | - } |
1584 | | - $undelete = SpecialPage::getTitleFor( 'Undelete' ); |
1585 | | - return $this->special->skin->link( $undelete, wfMsgHtml('diff'), array(), |
1586 | | - array( |
1587 | | - 'target' => $this->list->title->getPrefixedText(), |
1588 | | - 'diff' => 'prev', |
1589 | | - 'timestamp' => $this->revision->getTimestamp() |
1590 | | - ) ); |
1591 | | - } |
1592 | | -} |
1593 | | - |
1594 | | -/** |
1595 | | - * List for oldimage table items |
1596 | | - */ |
1597 | | -class RevDel_FileList extends RevDel_List { |
1598 | | - var $type = 'oldimage'; |
1599 | | - var $idField = 'oi_archive_name'; |
1600 | | - var $dateField = 'oi_timestamp'; |
1601 | | - var $authorIdField = 'oi_user'; |
1602 | | - var $authorNameField = 'oi_user_text'; |
1603 | | - var $storeBatch, $deleteBatch, $cleanupBatch; |
1604 | | - |
1605 | | - public function doQuery( $db ) { |
1606 | | - $archiveName = array(); |
1607 | | - foreach( $this->ids as $timestamp ) { |
1608 | | - $archiveNames[] = $timestamp . '!' . $this->title->getDBkey(); |
1609 | | - } |
1610 | | - return $db->select( 'oldimage', '*', |
1611 | | - array( |
1612 | | - 'oi_name' => $this->title->getDBkey(), |
1613 | | - 'oi_archive_name' => $archiveNames |
1614 | | - ), |
1615 | | - __METHOD__, |
1616 | | - array( 'ORDER BY' => 'oi_timestamp DESC' ) |
1617 | | - ); |
1618 | | - } |
1619 | | - |
1620 | | - public function newItem( $row ) { |
1621 | | - return new RevDel_FileItem( $this, $row ); |
1622 | | - } |
1623 | | - |
1624 | | - public function clearFileOps() { |
1625 | | - $this->deleteBatch = array(); |
1626 | | - $this->storeBatch = array(); |
1627 | | - $this->cleanupBatch = array(); |
1628 | | - } |
1629 | | - |
1630 | | - public function doPreCommitUpdates() { |
1631 | | - $status = Status::newGood(); |
1632 | | - $repo = RepoGroup::singleton()->getLocalRepo(); |
1633 | | - if ( $this->storeBatch ) { |
1634 | | - $status->merge( $repo->storeBatch( $this->storeBatch, FileRepo::OVERWRITE_SAME ) ); |
1635 | | - } |
1636 | | - if ( !$status->isOK() ) { |
1637 | | - return $status; |
1638 | | - } |
1639 | | - if ( $this->deleteBatch ) { |
1640 | | - $status->merge( $repo->deleteBatch( $this->deleteBatch ) ); |
1641 | | - } |
1642 | | - if ( !$status->isOK() ) { |
1643 | | - // Running cleanupDeletedBatch() after a failed storeBatch() with the DB already |
1644 | | - // modified (but destined for rollback) causes data loss |
1645 | | - return $status; |
1646 | | - } |
1647 | | - if ( $this->cleanupBatch ) { |
1648 | | - $status->merge( $repo->cleanupDeletedBatch( $this->cleanupBatch ) ); |
1649 | | - } |
1650 | | - return $status; |
1651 | | - } |
1652 | | - |
1653 | | - public function doPostCommitUpdates() { |
1654 | | - $file = wfLocalFile( $this->title ); |
1655 | | - $file->purgeCache(); |
1656 | | - $file->purgeDescription(); |
1657 | | - return Status::newGood(); |
1658 | | - } |
1659 | | - |
1660 | | - public function getSuppressBit() { |
1661 | | - return File::DELETED_RESTRICTED; |
1662 | | - } |
1663 | | -} |
1664 | | - |
1665 | | -/** |
1666 | | - * Item class for an oldimage table row |
1667 | | - */ |
1668 | | -class RevDel_FileItem extends RevDel_Item { |
1669 | | - var $file; |
1670 | | - |
1671 | | - public function __construct( $list, $row ) { |
1672 | | - parent::__construct( $list, $row ); |
1673 | | - $this->file = RepoGroup::singleton()->getLocalRepo()->newFileFromRow( $row ); |
1674 | | - } |
1675 | | - |
1676 | | - public function getId() { |
1677 | | - $parts = explode( '!', $this->row->oi_archive_name ); |
1678 | | - return $parts[0]; |
1679 | | - } |
1680 | | - |
1681 | | - public function canView() { |
1682 | | - return $this->file->userCan( File::DELETED_RESTRICTED ); |
1683 | | - } |
1684 | | - |
1685 | | - public function canViewContent() { |
1686 | | - return $this->file->userCan( File::DELETED_FILE ); |
1687 | | - } |
1688 | | - |
1689 | | - public function getBits() { |
1690 | | - return $this->file->getVisibility(); |
1691 | | - } |
1692 | | - |
1693 | | - public function setBits( $bits ) { |
1694 | | - # Queue the file op |
1695 | | - # FIXME: move to LocalFile.php |
1696 | | - if ( $this->isDeleted() ) { |
1697 | | - if ( $bits & File::DELETED_FILE ) { |
1698 | | - # Still deleted |
1699 | | - } else { |
1700 | | - # Newly undeleted |
1701 | | - $key = $this->file->getStorageKey(); |
1702 | | - $srcRel = $this->file->repo->getDeletedHashPath( $key ) . $key; |
1703 | | - $this->list->storeBatch[] = array( |
1704 | | - $this->file->repo->getVirtualUrl( 'deleted' ) . '/' . $srcRel, |
1705 | | - 'public', |
1706 | | - $this->file->getRel() |
1707 | | - ); |
1708 | | - $this->list->cleanupBatch[] = $key; |
1709 | | - } |
1710 | | - } elseif ( $bits & File::DELETED_FILE ) { |
1711 | | - # Newly deleted |
1712 | | - $key = $this->file->getStorageKey(); |
1713 | | - $dstRel = $this->file->repo->getDeletedHashPath( $key ) . $key; |
1714 | | - $this->list->deleteBatch[] = array( $this->file->getRel(), $dstRel ); |
1715 | | - } |
1716 | | - |
1717 | | - # Do the database operations |
1718 | | - $dbw = wfGetDB( DB_MASTER ); |
1719 | | - $dbw->update( 'oldimage', |
1720 | | - array( 'oi_deleted' => $bits ), |
1721 | | - array( |
1722 | | - 'oi_name' => $this->row->oi_name, |
1723 | | - 'oi_timestamp' => $this->row->oi_timestamp, |
1724 | | - 'oi_deleted' => $this->getBits() |
1725 | | - ), |
1726 | | - __METHOD__ |
1727 | | - ); |
1728 | | - return (bool)$dbw->affectedRows(); |
1729 | | - } |
1730 | | - |
1731 | | - public function isDeleted() { |
1732 | | - return $this->file->isDeleted( File::DELETED_FILE ); |
1733 | | - } |
1734 | | - |
1735 | | - /** |
1736 | | - * Get the link to the file. |
1737 | | - * Overridden by RevDel_ArchivedFileItem. |
1738 | | - */ |
1739 | | - protected function getLink() { |
1740 | | - global $wgLang, $wgUser; |
1741 | | - $date = $wgLang->timeanddate( $this->file->getTimestamp(), true ); |
1742 | | - if ( $this->isDeleted() ) { |
1743 | | - # Hidden files... |
1744 | | - if ( !$this->canViewContent() ) { |
1745 | | - $link = $date; |
1746 | | - } else { |
1747 | | - $link = $this->special->skin->link( |
1748 | | - $this->special->getTitle(), |
1749 | | - $date, array(), |
1750 | | - array( |
1751 | | - 'target' => $this->list->title->getPrefixedText(), |
1752 | | - 'file' => $this->file->getArchiveName(), |
1753 | | - 'token' => $wgUser->editToken( $this->file->getArchiveName() ) |
1754 | | - ) |
1755 | | - ); |
1756 | | - } |
1757 | | - return '<span class="history-deleted">' . $link . '</span>'; |
1758 | | - } else { |
1759 | | - # Regular files... |
1760 | | - $url = $this->file->getUrl(); |
1761 | | - return Xml::element( 'a', array( 'href' => $this->file->getUrl() ), $date ); |
1762 | | - } |
1763 | | - } |
1764 | | - /** |
1765 | | - * Generate a user tool link cluster if the current user is allowed to view it |
1766 | | - * @return string HTML |
1767 | | - */ |
1768 | | - protected function getUserTools() { |
1769 | | - if( $this->file->userCan( Revision::DELETED_USER ) ) { |
1770 | | - $link = $this->special->skin->userLink( $this->file->user, $this->file->user_text ) . |
1771 | | - $this->special->skin->userToolLinks( $this->file->user, $this->file->user_text ); |
1772 | | - } else { |
1773 | | - $link = wfMsgHtml( 'rev-deleted-user' ); |
1774 | | - } |
1775 | | - if( $this->file->isDeleted( Revision::DELETED_USER ) ) { |
1776 | | - return '<span class="history-deleted">' . $link . '</span>'; |
1777 | | - } |
1778 | | - return $link; |
1779 | | - } |
1780 | | - |
1781 | | - /** |
1782 | | - * Wrap and format the file's comment block, if the current |
1783 | | - * user is allowed to view it. |
1784 | | - * |
1785 | | - * @return string HTML |
1786 | | - */ |
1787 | | - protected function getComment() { |
1788 | | - if( $this->file->userCan( File::DELETED_COMMENT ) ) { |
1789 | | - $block = $this->special->skin->commentBlock( $this->file->description ); |
1790 | | - } else { |
1791 | | - $block = ' ' . wfMsgHtml( 'rev-deleted-comment' ); |
1792 | | - } |
1793 | | - if( $this->file->isDeleted( File::DELETED_COMMENT ) ) { |
1794 | | - return "<span class=\"history-deleted\">$block</span>"; |
1795 | | - } |
1796 | | - return $block; |
1797 | | - } |
1798 | | - |
1799 | | - public function getHTML() { |
1800 | | - global $wgLang; |
1801 | | - $data = |
1802 | | - wfMsg( |
1803 | | - 'widthheight', |
1804 | | - $wgLang->formatNum( $this->file->getWidth() ), |
1805 | | - $wgLang->formatNum( $this->file->getHeight() ) |
1806 | | - ) . |
1807 | | - ' (' . |
1808 | | - wfMsgExt( 'nbytes', 'parsemag', $wgLang->formatNum( $this->file->getSize() ) ) . |
1809 | | - ')'; |
1810 | | - $pageLink = $this->getLink(); |
1811 | | - |
1812 | | - return '<li>' . $this->getLink() . ' ' . $this->getUserTools() . ' ' . |
1813 | | - $data . ' ' . $this->getComment(). '</li>'; |
1814 | | - } |
1815 | | -} |
1816 | | - |
1817 | | -/** |
1818 | | - * List for filearchive table items |
1819 | | - */ |
1820 | | -class RevDel_ArchivedFileList extends RevDel_FileList { |
1821 | | - var $type = 'filearchive'; |
1822 | | - var $idField = 'fa_id'; |
1823 | | - var $dateField = 'fa_timestamp'; |
1824 | | - var $authorIdField = 'fa_user'; |
1825 | | - var $authorNameField = 'fa_user_text'; |
1826 | | - |
1827 | | - public function doQuery( $db ) { |
1828 | | - $ids = array_map( 'intval', $this->ids ); |
1829 | | - return $db->select( 'filearchive', '*', |
1830 | | - array( |
1831 | | - 'fa_name' => $this->title->getDBkey(), |
1832 | | - 'fa_id' => $ids |
1833 | | - ), |
1834 | | - __METHOD__, |
1835 | | - array( 'ORDER BY' => 'fa_id DESC' ) |
1836 | | - ); |
1837 | | - } |
1838 | | - |
1839 | | - public function newItem( $row ) { |
1840 | | - return new RevDel_ArchivedFileItem( $this, $row ); |
1841 | | - } |
1842 | | -} |
1843 | | - |
1844 | | -/** |
1845 | | - * Item class for a filearchive table row |
1846 | | - */ |
1847 | | -class RevDel_ArchivedFileItem extends RevDel_FileItem { |
1848 | | - public function __construct( $list, $row ) { |
1849 | | - RevDel_Item::__construct( $list, $row ); |
1850 | | - $this->file = ArchivedFile::newFromRow( $row ); |
1851 | | - } |
1852 | | - |
1853 | | - public function getId() { |
1854 | | - return $this->row->fa_id; |
1855 | | - } |
1856 | | - |
1857 | | - public function setBits( $bits ) { |
1858 | | - $dbw = wfGetDB( DB_MASTER ); |
1859 | | - $dbw->update( 'filearchive', |
1860 | | - array( 'fa_deleted' => $bits ), |
1861 | | - array( |
1862 | | - 'fa_id' => $this->row->fa_id, |
1863 | | - 'fa_deleted' => $this->getBits(), |
1864 | | - ), |
1865 | | - __METHOD__ |
1866 | | - ); |
1867 | | - return (bool)$dbw->affectedRows(); |
1868 | | - } |
1869 | | - |
1870 | | - protected function getLink() { |
1871 | | - global $wgLang, $wgUser; |
1872 | | - $date = $wgLang->timeanddate( $this->file->getTimestamp(), true ); |
1873 | | - $undelete = SpecialPage::getTitleFor( 'Undelete' ); |
1874 | | - $key = $this->file->getKey(); |
1875 | | - # Hidden files... |
1876 | | - if( !$this->canViewContent() ) { |
1877 | | - $link = $date; |
1878 | | - } else { |
1879 | | - $link = $this->special->skin->link( $undelete, $date, array(), |
1880 | | - array( |
1881 | | - 'target' => $this->list->title->getPrefixedText(), |
1882 | | - 'file' => $key, |
1883 | | - 'token' => $wgUser->editToken( $key ) |
1884 | | - ) |
1885 | | - ); |
1886 | | - } |
1887 | | - if( $this->isDeleted() ) { |
1888 | | - $link = '<span class="history-deleted">' . $link . '</span>'; |
1889 | | - } |
1890 | | - return $link; |
1891 | | - } |
1892 | | -} |
1893 | | - |
1894 | | -/** |
1895 | | - * List for logging table items |
1896 | | - */ |
1897 | | -class RevDel_LogList extends RevDel_List { |
1898 | | - var $type = 'logging'; |
1899 | | - var $idField = 'log_id'; |
1900 | | - var $dateField = 'log_timestamp'; |
1901 | | - var $authorIdField = 'log_user'; |
1902 | | - var $authorNameField = 'log_user_text'; |
1903 | | - |
1904 | | - public function doQuery( $db ) { |
1905 | | - global $wgMessageCache; |
1906 | | - $wgMessageCache->loadAllMessages(); |
1907 | | - $ids = array_map( 'intval', $this->ids ); |
1908 | | - return $db->select( 'logging', '*', |
1909 | | - array( 'log_id' => $ids ), |
1910 | | - __METHOD__, |
1911 | | - array( 'ORDER BY' => 'log_id DESC' ) |
1912 | | - ); |
1913 | | - } |
1914 | | - |
1915 | | - public function newItem( $row ) { |
1916 | | - return new RevDel_LogItem( $this, $row ); |
1917 | | - } |
1918 | | - |
1919 | | - public function getSuppressBit() { |
1920 | | - return Revision::DELETED_RESTRICTED; |
1921 | | - } |
1922 | | - |
1923 | | - public function getLogAction() { |
1924 | | - return 'event'; |
1925 | | - } |
1926 | | - |
1927 | | - public function getLogParams( $params ) { |
1928 | | - return array( |
1929 | | - implode( ',', $params['ids'] ), |
1930 | | - "ofield={$params['oldBits']}", |
1931 | | - "nfield={$params['newBits']}" |
1932 | | - ); |
1933 | | - } |
1934 | | -} |
1935 | | - |
1936 | | -/** |
1937 | | - * Item class for a logging table row |
1938 | | - */ |
1939 | | -class RevDel_LogItem extends RevDel_Item { |
1940 | | - public function canView() { |
1941 | | - return LogEventsList::userCan( $this->row, Revision::DELETED_RESTRICTED ); |
1942 | | - } |
1943 | | - |
1944 | | - public function canViewContent() { |
1945 | | - return true; // none |
1946 | | - } |
1947 | | - |
1948 | | - public function getBits() { |
1949 | | - return $this->row->log_deleted; |
1950 | | - } |
1951 | | - |
1952 | | - public function setBits( $bits ) { |
1953 | | - $dbw = wfGetDB( DB_MASTER ); |
1954 | | - $dbw->update( 'recentchanges', |
1955 | | - array( |
1956 | | - 'rc_deleted' => $bits, |
1957 | | - 'rc_patrolled' => 1 |
1958 | | - ), |
1959 | | - array( |
1960 | | - 'rc_logid' => $this->row->log_id, |
1961 | | - 'rc_timestamp' => $this->row->log_timestamp // index |
1962 | | - ), |
1963 | | - __METHOD__ |
1964 | | - ); |
1965 | | - $dbw->update( 'logging', |
1966 | | - array( 'log_deleted' => $bits ), |
1967 | | - array( |
1968 | | - 'log_id' => $this->row->log_id, |
1969 | | - 'log_deleted' => $this->getBits() |
1970 | | - ), |
1971 | | - __METHOD__ |
1972 | | - ); |
1973 | | - return (bool)$dbw->affectedRows(); |
1974 | | - } |
1975 | | - |
1976 | | - public function getHTML() { |
1977 | | - global $wgLang; |
1978 | | - |
1979 | | - $date = htmlspecialchars( $wgLang->timeanddate( $this->row->log_timestamp ) ); |
1980 | | - $paramArray = LogPage::extractParams( $this->row->log_params ); |
1981 | | - $title = Title::makeTitle( $this->row->log_namespace, $this->row->log_title ); |
1982 | | - |
1983 | | - // Log link for this page |
1984 | | - $loglink = $this->special->skin->link( |
1985 | | - SpecialPage::getTitleFor( 'Log' ), |
1986 | | - wfMsgHtml( 'log' ), |
1987 | | - array(), |
1988 | | - array( 'page' => $title->getPrefixedText() ) |
1989 | | - ); |
1990 | | - // Action text |
1991 | | - if( !$this->canView() ) { |
1992 | | - $action = '<span class="history-deleted">' . wfMsgHtml('rev-deleted-event') . '</span>'; |
1993 | | - } else { |
1994 | | - $action = LogPage::actionText( $this->row->log_type, $this->row->log_action, $title, |
1995 | | - $this->special->skin, $paramArray, true, true ); |
1996 | | - if( $this->row->log_deleted & LogPage::DELETED_ACTION ) |
1997 | | - $action = '<span class="history-deleted">' . $action . '</span>'; |
1998 | | - } |
1999 | | - // User links |
2000 | | - $userLink = $this->special->skin->userLink( $this->row->log_user, |
2001 | | - User::WhoIs( $this->row->log_user ) ); |
2002 | | - if( LogEventsList::isDeleted($this->row,LogPage::DELETED_USER) ) { |
2003 | | - $userLink = '<span class="history-deleted">' . $userLink . '</span>'; |
2004 | | - } |
2005 | | - // Comment |
2006 | | - $comment = $wgLang->getDirMark() . $this->special->skin->commentBlock( $this->row->log_comment ); |
2007 | | - if( LogEventsList::isDeleted($this->row,LogPage::DELETED_COMMENT) ) { |
2008 | | - $comment = '<span class="history-deleted">' . $comment . '</span>'; |
2009 | | - } |
2010 | | - return "<li>($loglink) $date $userLink $action $comment</li>"; |
2011 | | - } |
2012 | | -} |
Index: trunk/phase3/includes/RevisionDelete.php |
— | — | @@ -166,12 +166,17 @@ |
167 | 167 | if ($existResult !== true) { |
168 | 168 | $key = 'archive'; |
169 | 169 | $Ids[$k] = $existResult; |
170 | | - } elseif ($key != $originalKey) { |
| 170 | + } else { |
171 | 171 | // Undeleted revision amidst deleted ones |
172 | 172 | unset($Ids[$k]); |
173 | 173 | $undeletedRevisions[] = $id; |
174 | 174 | } |
175 | 175 | } |
| 176 | + |
| 177 | + if ( $key == $originalKey ) { |
| 178 | + $Ids = $undeletedRevisions; |
| 179 | + $undeletedRevisions = array(); |
| 180 | + } |
176 | 181 | } |
177 | 182 | |
178 | 183 | // Diff link for single rev deletions |