Skip to content

Instantly share code, notes, and snippets.

@SLaks
Created August 2, 2021 20:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SLaks/91d18f078bc5316727f8f59a3e1eebc4 to your computer and use it in GitHub Desktop.
Save SLaks/91d18f078bc5316727f8f59a3e1eebc4 to your computer and use it in GitHub Desktop.
ShulCloud Import Script
// Run this in LINQPad, and add a reference to my https://github.com/ShomreiTorah/Libraries/tree/master/ShomreiTorah.Common
const string domain = "<TODO: insert domain here>";
static readonly Regex parseId = new Regex(@"action=edit_addresses&id=(\d+)");
static readonly Regex findSccsrf = new Regex(@"<input type=""hidden"" name=""sccsrf"" value=""(\w+)""/>");
bool dryRun = false;
async Task Main() {
var cookies = new CookieContainer();
cookies.Add(new Cookie("login_13530095", "TODO: Insert Cookie") { Domain = domain });
cookies.Add(new Cookie("PHPSESSID", "TODO: Insert Cookie") { Domain = domain });
cookies.Add(new Cookie("cookiesession1", "TODO: Insert Cookie") { Domain = domain });
using (var httpHandler = new HttpClientHandler { CookieContainer = cookies })
using (var http = new HttpClient(httpHandler) { BaseAddress = new Uri("https://" + domain) })
using (var reader = DB.OpenFile($@"{Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)}\TODO\ Members.xlsx").ExecuteReader("SELECT * FROM [Sheet1$]")) {
string GetCsrfToken() {
var responseMessage = http.GetAsync("/admin/settings.php?action=edit").GetAwaiter().GetResult();
string response = responseMessage.Content.ReadAsStringAsync().GetAwaiter().GetResult();
return findSccsrf.Match(response).Groups[1].Value;
}
string SendRequest(string path, HttpContent content) {
if (dryRun) {
return @"
action=edit_addresses&id=99999
<input type=""hidden"" name=""sccsrf"" value=""XSRF123ABC""/>";
}
var responseMessage = http.PostAsync(path, content).GetAwaiter().GetResult();
string response = responseMessage.Content.ReadAsStringAsync().GetAwaiter().GetResult();
if (response.Contains("Security Error")) throw new Exception($"Security Error from {path}");
return response;
}
while (reader.Read()) {
var lastName = reader.GetField<string>("Last Name");
var hisName = reader.GetField<string>("His Name");
var herName = reader.GetField<string>("Her Name");
if (lastName == null) {
Console.WriteLine($"Skipping {lastName}, {hisName} & {herName} due to nulls");
continue;
}
Console.Write($"Entering {lastName}, {hisName} & {herName}... ");
// TODO: Update this logic to match your needs & IDs
var type = reader.GetField<string>("Membership status")?.Trim();
var isFriend = type == "Friend of Shul";
var isRecurring = type == "recurring";
var tags = new List<string>() { "977784" };
if (isRecurring) tags.Add("977794");
if (type.StartsWith("paid")) tags.Add("980759");
if (isFriend) tags.Add("980760");
var response = SendRequest($"/admin/members.php?action=add", new FormUrlEncodedContent(ToPairs(new string[][]{
new []{"sccsrf", GetCsrfToken()},
new []{"action", "save_account"},
new []{"redirect", "/admin/members.php?action=edit_addresses"},
new []{"id", "0"},
new []{"info[account_type_id]", isFriend ? "155871" : "155869"},
new []{"info[is_account_name_overridden]", "N"},
new []{"info[name]", $"{lastName}, {hisName} & {herName}"},
new []{"info[is_active]", "Y"},
new []{"switch_adults", "no"},
new []{"adult1[first_name]",hisName},
new []{"adult1[last_name]", lastName},
new []{"adult1[member_type]", "120856"},
new []{"adult1_gender[gender]", "M"},
new []{"adult1[email]", reader.GetField<string>("Husband Email")},
new []{"adult1[tribe]", "0"},
new []{"adult1_tags", tags.Join(",")},
new []{"adult1_perms[]", "11"},
new []{"adult1_perms[]", "12"},
new []{"adult1_perms[]", "10"},
new []{"adult2[first_name]", herName},
new []{"adult2[last_name]", lastName},
new []{"adult2[member_type]", "120856"},
new []{"adult2_gender[gender]", "F"},
new []{"adult2[email]", reader.GetField<string>("Wife Email")},
new []{"adult2[tribe]", "0"},
new []{"adult2_tags", tags.Join(",")},
new []{"adult2_perms[]", "11"},
new []{"adult2_perms[]", "12"},
new []{"adult2_perms[]", "10"},
new []{"children[clone][delete]", "N"},
new []{"children[clone][member_type]", "120857"},
new []{"children_gender[clone][gender]", "custom"},
new []{"children[clone][tribe]", "0"},
new []{"other[marital_status_id]", "2"},
new []{"info[account_billing_type_id]", "0"},
new []{"loaded_multiselects", "Y"},
new []{"unloaded_multiselects", "Y"},
})));
string id = parseId.Match(response).Groups[1].Value;
Console.Write($"ID: {id}... ");
SendRequest($"/admin/members.php?action=edit_addresses&id={id}", new FormUrlEncodedContent(ToPairs(new string[][]{
new [] {"sccsrf", GetCsrfToken()},
new [] {"action", "save_addresses"},
new [] {"id", id},
new [] {"site_account_default_address", "new_1"},
new [] {"site_account_default_billing_address", "new_1"},
new [] {"site_account_addresses[new][1][delete]", "N"},
new [] {"site_account_addresses[new][1][short_name]", "Home"},
new [] {"site_account_addresses[new][1][is_mail_name_overridden]", "N"},
new [] {"site_account_addresses[new][1][mail_name]", $"{hisName} {lastName}"},
new [] {"site_account_addresses[new][1][address]", reader.GetField<string>("Address")},
new [] {"site_account_addresses[new][1][address2]"," "},
new [] {"site_account_addresses[new][1][city]", reader.GetField<string>("City")},
new [] {"use_state_select", "true"},
new [] {"site_account_addresses[new][1][state]", reader.GetField<string>("State")},
new [] {"site_account_addresses[new][1][zip]", reader.GetField<object>("Zip")?.ToString()},
new [] {"site_account_addresses[new][1][country]", "USA"},
new [] {"site_account_addresses[new][1][phone]"," "},
new [] {"site_account_addresses[new][1][annual_default_start_month]", "00"},
new [] {"site_account_addresses[new][1][annual_default_billing_start_month]", "00"},
new [] {"info[update_phone_with_address]", "Y"},
new [] {"loaded_multiselects", "Y"},
new [] {"unloaded_multiselects", "Y"},
})));
Console.WriteLine("Done!");
//if (!dryRun) break;
}
}
}
static IEnumerable<KeyValuePair<string, string>> ToPairs(string[][] pairs) {
return pairs.Where(a => a != null && a[1] != null).Select(p => new KeyValuePair<string, string>(p[0], p[1]));
}
// Define other methods and classes here
} static class Extensions {
public static T GetField<T>(this IDataRecord reader, string name) {
if (reader.IsDBNull(reader.GetOrdinal(name))) return default(T);
return (T)reader[name];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment