Slack is an amazing chat tool used by lots of software development teams. My company uses it for chat and exchanging ideas. Its been running fine for about 2.5 years. It has free and paid plans. We’re using the free plan because it does everything we need, until today…
We got the notification that we’re using more files than the free plan allows. There is nothing in the admin panel for a free account to delete unwanted files. It recommends finding the files one at a time in the app and removing them. With 2.5 years of data, that is a lot of files. So I went in search of a way to perform this programmatically as I’m a software developer!
api.slack.com is the place to get started. From here logged into my admin account, I found an API to list files and another to delete them. The whole program as a C# console is listed below. I did this in a hurry to correct the issue and get us sharing content again.
The image below is a screen shot of the end of a run in the program. It deleted 644 Mb of data.
Its worth nothing that this program isn’t perfect. I didn’t map all the fields that come back from the file listing. It also doesn’t delete all the files. I had to run it several times before it couldn’t find any more files to delete. Its also been about 12 hours since I ran the program and Slack still shows us over our file limit. I’m hoping it’ll re-evaluate that number by Monday morning as the API said we deleted the files and doesn’t show any more.
Update — Over the weekend the file size updated and we have room again. Something is still off as I deleted all files that were more than 10 days old and it says we still have 2.6 Gb of files, but its an improvement!
Good luck getting rid of those pesky uploaded files in your Free Slack!
Hogan Haake
using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System.Net; namespace SlackFilesDelete { class Program { public const string Token = "?token=xoxp-xxxxxxxxxxx-xxxxxxxxxxx-xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&pretty=1"; static void Main(string[] args) { Console.WriteLine("Starting to delete old slack files."); Dictionary<string, string> headers = new Dictionary<string, string>(); string fileListURI = "https://slack.com/api/files.list" + Token; fileListURI += "&ts_to=" + TimeToUnixEpic(DateTime.UtcNow.AddDays(-10)); int fileCount = 1; int currentPage = 0; long deletedSize = 0; while (1 == 1) { string response = RestApiRequestHelper(fileListURI + "&page=" + currentPage++, "get", "application/json", "application/json", headers, null); FileListResponse responseData = JsonConvert.DeserializeObject<FileListResponse>(response); if (!responseData.OK) { Console.WriteLine("File List Broken!!!"); break; } else { if (responseData.Files.Count == 0) { Console.WriteLine("Nothing left to delete, quitting!"); break; } string fileDeleteURI = "https://slack.com/api/files.delete" + Token; foreach (SlackFileData fileData in responseData.Files) { string deleteResponse = RestApiRequestHelper(fileDeleteURI + "&file=" + fileData.id, "get", "application/json", "application/json", headers, null); if (deleteResponse.Contains("true")) { Console.WriteLine($"{fileCount++}:: Deleted file:{fileData.Name} Size:{fileData.Size} Date:{fileData.FileDate} Title:{fileData.Title} "); deletedSize += fileData.Size; } System.Threading.Thread.Sleep(1100); } Console.WriteLine("----- Getting more files to delete ---"); Console.WriteLine("Total Deleted Bytes:: " + deletedSize.ToString("N0")); } System.Threading.Thread.Sleep(1100); } Console.WriteLine("Done. Press 'any key'"); Console.ReadLine(); } public static string RestApiRequestHelper(string url, string verb, string content, string accept, Dictionary<string, string> headers, string data) { string returnStr = string.Empty; try { HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create(url); if (content != null) myReq.ContentType = content; myReq.Method = verb; if (!string.IsNullOrEmpty(accept)) myReq.Accept = accept; var myResp = myReq.GetResponse(); using (var htmlStream = new StreamReader(myResp.GetResponseStream())) { returnStr = htmlStream.ReadToEnd(); } } catch (Exception e) { } return returnStr; } public static int TimeToUnixEpic(DateTime utcTime) { TimeSpan t = utcTime - new DateTime(1970, 1, 1); return (int)t.TotalSeconds; } } public class FileListResponse { public bool OK { get; set; } public List<SlackFileData> Files { get; set; } public Paging Page { get; set; } } public class Paging { public int Page { get; set; } public int Pages { get; set; } } public class SlackFileData { public string id { get; set; } public string Name { get; set; } public string Title { get; set; } public int Size { get; set; } public int Timestamp { get; set; } public string FileDate { get { DateTime value = new DateTime(1970, 1, 1).AddSeconds(Timestamp); return value.ToShortDateString() + " " + value.ToShortTimeString(); } } } }