ghidra-master/Ghidra/Features/Base/ghidra_scripts/RemoveUserCheckoutsScript.java
/* ###
 * IP: GHIDRA
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
//Script to allow repository admins the ability to terminate multiple file checkouts belonging to a single user.
//@category MultiUser

import java.io.IOException;

import docking.widgets.OptionDialog;
import ghidra.app.script.GhidraScript;
import ghidra.framework.client.RepositoryAdapter;
import ghidra.framework.model.Project;
import ghidra.framework.model.ProjectData;
import ghidra.framework.remote.RepositoryItem;
import ghidra.framework.remote.User;
import ghidra.framework.store.ItemCheckoutStatus;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;

public class RemoveUserCheckoutsScript extends GhidraScript {

	@Override
	protected void run() throws Exception {
		
		Project project = state.getProject();
		
		ProjectData projectData = project.getProjectData();
		
		RepositoryAdapter repository = projectData.getRepository();
		if (repository == null) {
			printerr("Project is not a shared project");
			return;
		}
		
		User currentUser = repository.getUser();
		if (!currentUser.isAdmin()) {
			printerr("You are not a repository administrator for " + repository.getName());
			return;
		}
		
		String uname = askString("Remove User Checkouts" , "Enter user ID to be cleared");
		
		boolean found = false;
		for (User u : repository.getUserList()) {
			if (uname.equals(u.getName())) {
				found = true;
				break;
			}
		}
		if (!found) {
			if (OptionDialog.showYesNoDialogWithNoAsDefaultButton(null, "User Name Confirmation",
					"User '" + uname + "' not a registered server user.\nDo you still want to search for and remove checkouts for this user?") != OptionDialog.YES_OPTION) {
				return;
			}
		}
		
		if (projectData.getFileCount() > 1000) {
			if (OptionDialog.showYesNoDialogWithNoAsDefaultButton(null, "Large Repository Confirmation",
					"Repository contains a large number of failes and could be slow to search.\nDo you still want to search for and remove checkouts?") != OptionDialog.YES_OPTION) {
				return;
			}
		}
		
		int count = removeCheckouts(repository, "/", uname, monitor);
		popup("Removed " + count + " checkouts");
		
	}
	
	private String getPath(String folderPath, String childName) {
		if (!folderPath.endsWith("/")) {
			folderPath += "/";
		}
		return folderPath + childName;
	}
	
	private int removeCheckouts(RepositoryAdapter repository, String folderPath, String uid, TaskMonitor monitor) throws IOException, CancelledException {
		int count = 0;
		for (RepositoryItem item : repository.getItemList(folderPath)) {
			monitor.checkCancelled();
			count += removeCheckouts(repository, item, uid);
		}
		for (String subfolder : repository.getSubfolderList(folderPath)) {
			count += removeCheckouts(repository, getPath(folderPath, subfolder), uid, monitor);
		}
		return count;
	}
	
	private int removeCheckouts(RepositoryAdapter repository, RepositoryItem item, String uid) throws IOException {
		int count = 0;
		ItemCheckoutStatus[] checkouts = repository.getCheckouts(item.getParentPath(), item.getName());
		for (ItemCheckoutStatus checkout : checkouts) {
			if (uid.equals(checkout.getUser())) {
				try {
					repository.terminateCheckout(item.getParentPath(), item.getName(), checkout.getCheckoutId(), false);
					++count;
				} catch (IOException e) {
					printerr("Failed to remove checkout: " + e.getMessage());
				}
			}
		}
		return count;
	}

}
