using System.Threading.Tasks; using Dapper; using Microsoft.EntityFrameworkCore; namespace BTCPayServer.Data; public static partial class ApplicationDbContextExtensions { /// /// StoreBlob.NoActiveUser is set up to `true` if users have a store where there are /// no active users /// /// /// public static Task UpdateStoreNoActiveUserForUsers(this DbSet dbSet, string[] userIds) { DynamicParameters parameters = new(); parameters.Add("userIds", userIds); return dbSet.UpdateStoreNoActiveUserCore(""" SELECT DISTINCT us."StoreDataId" AS store_id FROM unnest(@userIds::text[]) AS u("UserId") JOIN "UserStore" us ON us."ApplicationUserId" = u."UserId" """, parameters); } public static Task UpdateStoreNoActiveUserForStores(this DbSet dbSet, string[] storeIds) { DynamicParameters parameters = new(); parameters.Add("stores", storeIds); return dbSet.UpdateStoreNoActiveUserCore(""" SELECT DISTINCT store_id FROM unnest(@stores::text[]) AS u(store_id) """, parameters); } public static Task UpdateStoreNoActiveUserCore(this DbSet dbSet, string selectStoresSql, DynamicParameters parameters) => dbSet.GetDbConnection() .ExecuteAsync(GetUpdateStoreNoActiveUserQuery(selectStoresSql), parameters); internal static string GetUpdateStoreNoActiveUserQuery(string selectStoresSql) => $$""" WITH -- Select all the stores belonging to the userIds stores AS ( {{selectStoresSql}} ), -- Count all active users of the store active_users AS ( SELECT s."Id", COUNT(u."Id") FILTER (WHERE u."LockoutEnd" IS NULL OR u."LockoutEnd" <= NOW()) AS active_users FROM stores st JOIN "Stores" s ON s."Id" = st.store_id LEFT JOIN "UserStore" us ON us."StoreDataId" = s."Id" LEFT JOIN "AspNetUsers" u ON u."Id" = us."ApplicationUserId" GROUP BY s."Id" ), -- If the total is 0, then the store should have noActiveUser set to true expected_disabled AS ( SELECT s."Id", COALESCE(s."StoreBlob"->'noActiveUser' = 'true'::JSONB, false) current_value, t.active_users = 0 expected_value FROM active_users t JOIN "Stores" s ON s."Id" = t."Id" ) -- Update only the stores not having expected values. UPDATE "Stores" s SET "StoreBlob" = jsonb_set("StoreBlob", '{noActiveUser}', to_jsonb(ed.expected_value)) FROM expected_disabled ed WHERE s."Id" = ed."Id" AND ed.expected_value <> ed.current_value; """; }