def validations(): confirm_write_access() organizations_subquery = ~OrganisationMembership.query \ .filter(OrganisationMembership.role == "admin") \ .filter(OrganisationMembership.organisation_id == Organisation.id) \ .exists() organisations_without_admins = Organisation.query.filter(organizations_subquery).all() services_subquery = ~ServiceMembership.query \ .filter(ServiceMembership.role == "admin") \ .filter(ServiceMembership.service_id == Service.id) \ .exists() services_without_admins = Service.query.filter(services_subquery).all() organisation_invitations = OrganisationInvitation.query \ .options(joinedload(OrganisationInvitation.organisation)) \ .options(joinedload(OrganisationInvitation.user)) \ .all() return { "organisations": organisations_without_admins, "organisation_invitations": organisation_invitations, "services": services_without_admins }, 200
def get_platform_admins(): confirm_write_access() config = current_app.app_config admin_users_upgrade = config.feature.admin_users_upgrade admin_users = [u.uid for u in config.admin_users] platform_admins = User.query.filter(User.uid.in_(admin_users)).all() return {"platform_admins": platform_admins, "admin_users_upgrade": admin_users_upgrade}, 200
def save_organisation(): confirm_write_access() data = current_request.get_json() _clear_api_keys(data) cleanse_short_name(data) data["identifier"] = str(uuid.uuid4()) administrators = data.get("administrators", []) intended_role = data.get("intended_role", "admin") message = data.get("message", None) res = save(Organisation, custom_json=data) user = User.query.get(current_user_id()) organisation = res[0] for administrator in administrators: invitation = OrganisationInvitation(hash=generate_token(), message=message, invitee_email=administrator, organisation_id=organisation.id, user_id=user.id, intended_role=intended_role, expiry_date=default_expiry_date(), created_by=user.uid) invitation = db.session.merge(invitation) mail_organisation_invitation({ "salutation": "Dear", "invitation": invitation, "base_url": current_app.app_config.base_url, "recipient": administrator }, organisation, [administrator]) mail_platform_admins(organisation) return res
def add_collaborations_services(): data = current_request.get_json() organisation_id = int(data["organisation_id"]) service_id = int(data["service_id"]) confirm_organisation_admin_or_manager(organisation_id) # Ensure that the connection is allowed service = Service.query.get(service_id) is_allowed = organisation_id in list( map(lambda org: org.id, service.allowed_organisations)) or service.access_allowed_for_all if not is_allowed: raise BadRequest("not_allowed_organisation") if not service.automatic_connection_allowed and not service.access_allowed_for_all: raise BadRequest("automatic_connection_not_allowed") organisation = Organisation.query.get(organisation_id) if organisation.services_restricted: confirm_write_access() organisation.services.append(service) db.session.merge(organisation) # Create groups from service_groups for collaboration in organisation.collaborations: create_service_groups(service, collaboration) return None, 201
def clear_audit_logs(): confirm_write_access() if not current_app.app_config.feature.seed_allowed: raise BadRequest("clear-audit-logs not allowed in this environment") db.session.execute(text("DELETE FROM audit_logs")) return {}, 201
def run_seed(): confirm_write_access() if not current_app.app_config.feature.seed_allowed: raise BadRequest("seed not allowed in this environment") seed(db, current_app.app_config, skip_seed=False, perf_test=True) return {}, 201
def all_service_request_connections_by_service(service_id): confirm_write_access(service_id, override_func=is_service_admin) return ServiceConnectionRequest.query \ .join(ServiceConnectionRequest.collaboration) \ .join(ServiceConnectionRequest.requester) \ .options(contains_eager(ServiceConnectionRequest.collaboration)) \ .options(contains_eager(ServiceConnectionRequest.requester)) \ .filter(ServiceConnectionRequest.service_id == service_id) \ .all(), 200
def clean_slate(): confirm_write_access() if not current_app.app_config.feature.seed_allowed: raise BadRequest("clean_slate not allowed in this environment") seed(db, current_app.app_config, skip_seed=True) return {}, 201
def scheduled_jobs(): confirm_write_access() if not hasattr(current_app, "scheduler"): return [], 200 jobs = current_app.scheduler.get_jobs() return [{"name": job.name, "next_run_time": job.next_run_time} for job in jobs], 200
def delete_all_services(collaboration_id): confirm_collaboration_admin(collaboration_id) collaboration = Collaboration.query.get(collaboration_id) if collaboration.organisation.services_restricted: confirm_write_access() collaboration.services = [] db.session.merge(collaboration) return None, 204
def test_is_admin(self): with self.app.app_context(): session["user"] = {"uid": "urn:john", "admin": True, "confirmed_admin": True} self.assertTrue(is_admin_user({"uid": "urn:john"})) self.assertTrue(is_application_admin()) confirm_allow_impersonation() request_context.is_authorized_api_call = False confirm_write_access()
def delete_collaborations_services(collaboration_id, service_id): confirm_collaboration_admin(collaboration_id) collaboration = Collaboration.query.get(collaboration_id) if collaboration.organisation.services_restricted: confirm_write_access() collaboration.services.remove(Service.query.get(service_id)) db.session.merge(collaboration) return {'collaboration_id': collaboration_id, 'service_id': service_id}, 204
def delete_organisations_services(organisation_id, service_id): confirm_organisation_admin_or_manager(organisation_id) organisation = Organisation.query.get(organisation_id) if organisation.services_restricted: confirm_write_access() organisation.services.remove(Service.query.get(service_id)) db.session.merge(organisation) return None, 204
def do_db_stats(): confirm_write_access() results = [] tables = list(map(lambda t: str(t.name), metadata.sorted_tables)) tables.append("audit_logs") for table in tables: rows = db.session.execute(text(f"SELECT COUNT(*) FROM `{table}`")) for row in rows: results.append({"name": table, "count": row[0]}) return sorted(results, key=lambda k: k["count"], reverse=True), 200
def activate(): body = current_request.get_json() if "collaboration_id" in body: confirm_collaboration_admin(body["collaboration_id"], org_manager_allowed=False) elif "organisation_id" in body: confirm_organisation_admin(body["organisation_id"]) else: confirm_write_access() user = User.query.get(body["user_id"]) user.suspended = False retention = current_app.app_config.retention user.last_login_date = datetime.datetime.now() - datetime.timedelta(days=retention.allowed_inactive_period_days) user.suspend_notifications = [] db.session.merge(user) create_suspend_notification(user, retention, current_app, True) return {}, 201
def organisation_search(): confirm_write_access(override_func=is_service_admin) res = [] q = query_param("q") if q and len(q): base_query = "SELECT id, name, description, category, logo, short_name FROM organisations " not_wild_card = "*" not in q if not_wild_card: q = replace_full_text_search_boolean_mode_chars(q) base_query += f"WHERE MATCH (name, description) AGAINST (:q IN BOOLEAN MODE) " \ f"AND id > 0 ORDER BY NAME LIMIT {full_text_search_autocomplete_limit}" sql = text(base_query if not_wild_card else base_query + " ORDER BY NAME") if not_wild_card: sql = sql.bindparams(bindparam("q", type_=String)) result_set = db.engine.execute(sql, {"q": f"{q}*"}) if not_wild_card else db.engine.execute(sql) res = [{"id": row[0], "name": row[1], "description": row[2], "category": row[3], "logo": row[4], "short_name": row[5]} for row in result_set] return res, 200
def add_allowed_organisations(service_id): confirm_write_access() service = Service.query.get(service_id) data = current_request.get_json() allowed_organisations = data.get("allowed_organisations", None) org_sql = f"DELETE FROM services_organisations WHERE service_id = {service_id}" coll_sql = f"DELETE sc FROM services_collaborations sc INNER JOIN collaborations c on c.id = sc.collaboration_id " \ f"WHERE sc.service_id = {service_id}" need_to_delete = not bool(allowed_organisations) if allowed_organisations: # find delta, e.g. which one to remove and which ones to add current_allowed = [org.id for org in service.allowed_organisations] new_allowed = [int(value["organisation_id"]) for value in allowed_organisations] to_remove = [org_id for org_id in current_allowed if org_id not in new_allowed] to_append = [org_id for org_id in new_allowed if org_id not in current_allowed] for org_id in to_remove: service.allowed_organisations.remove(Organisation.query.get(org_id)) for org_id in to_append: service.allowed_organisations.append(Organisation.query.get(org_id)) if to_remove: need_to_delete = True org_del_ids = ",".join([str(org_id) for org_id in to_remove]) org_sql += f" AND organisation_id in ({org_del_ids})" coll_sql += f" AND c.organisation_id in ({org_del_ids})" else: service.allowed_organisations.clear() db.session.merge(service) if need_to_delete: db.engine.execute(text(org_sql)) db.engine.execute(text(coll_sql)) return None, 201
def connect_service_collaboration(service_id, collaboration_id, force=False): # Ensure that the connection is allowed service = Service.query.get(service_id) organisation_id = Collaboration.query.get(collaboration_id).organisation_id organisation_not_allowed = organisation_id not in list(map(lambda org: org.id, service.allowed_organisations)) if organisation_not_allowed and not service.access_allowed_for_all: raise BadRequest("not_allowed_organisation") if not force and not service.automatic_connection_allowed: raise BadRequest("automatic_connection_not_allowed") collaboration = Collaboration.query.get(collaboration_id) if collaboration.organisation.services_restricted: confirm_write_access() collaboration.services.append(service) db.session.merge(collaboration) # Create groups from service_groups create_service_groups(service, collaboration) return 1
def update_organisation(): def override_func(): user_id = current_user_id() organisation_id = current_request.get_json()["id"] count = OrganisationMembership.query \ .filter(OrganisationMembership.user_id == user_id) \ .filter(OrganisationMembership.organisation_id == organisation_id) \ .filter(OrganisationMembership.role == "admin") \ .count() return count > 0 confirm_write_access(override_func=override_func) data = current_request.get_json() _clear_api_keys(data) cleanse_short_name(data) organisation = Organisation.query.get(data["id"]) if organisation.short_name != data["short_name"]: for collaboration in organisation.collaborations: collaboration.global_urn = f"{data['short_name']}:{collaboration.short_name}" db.session.merge(collaboration) for group in collaboration.groups: group.global_urn = f"{data['short_name']}:{collaboration.short_name}:{group.short_name}" db.session.merge(group) if not is_application_admin() and organisation.services_restricted: data["services_restricted"] = True # Corner case: user removed name and added the exact same name again, prevent duplicate entry existing_names = [sho.name for sho in organisation.schac_home_organisations] if "schac_home_organisations" in data: if len([sho for sho in data["schac_home_organisations"] if not sho.get("id") and sho["name"] in existing_names]) > 0: organisation.schac_home_organisations.clear() return update(Organisation, custom_json=data, allow_child_cascades=False, allowed_child_collections=["schac_home_organisations"])
def _do_get_services(restrict_for_current_user=False, include_counts=False): def override_func(): return is_collaboration_admin() or _is_org_member() or is_service_admin() confirm_write_access(override_func=override_func) query = Service.query \ .options(selectinload(Service.allowed_organisations)) \ .options(selectinload(Service.service_connection_requests)) if restrict_for_current_user: query = query.join(Service.service_memberships) \ .filter(ServiceMembership.user_id == current_user_id()) services = query.all() if not include_counts: return services, 200 query = """ select s.id as id, (select count(so.id) from services_organisations so where so.service_id = s.id) as so_count , ((select count(sc.id) from services_collaborations sc where sc.service_id = s.id) + (select count(c.id) from collaborations c where c.organisation_id in ( select so.organisation_id from services_organisations so where so.service_id = s.id ) and c.id not in ( select sc.collaboration_id from services_collaborations sc where sc.service_id = s.id ))) as c_count from services s """ if restrict_for_current_user: query += f" where s.id in ({','.join([str(s.id) for s in services])})" result_set = db.engine.execute(text(query)) services_json = jsonify(services).json services_json_dict = {s["id"]: s for s in services_json} for row in result_set: service_json = services_json_dict.get(row[0]) service_json["organisations_count"] = row[1] service_json["collaborations_count"] = row[2] return services_json, 200
def do_expire_collaboration(): confirm_write_access() from server.cron.collaboration_expiration import expire_collaborations return expire_collaborations(current_app), 201
def delete_organisation(id): confirm_write_access() return delete(Organisation, id)
def organisation_all(): confirm_write_access() organisations = Organisation.query.all() return organisations, 200
def find_by_id(): confirm_write_access() return _user_query() \ .options(joinedload(User.service_aups) .subqueryload(ServiceAup.service)) \ .filter(User.id == query_param("id")).one(), 200
def suspended(): confirm_write_access() return User.query.filter(User.suspended == True).all(), 200 # noqa: E712
def do_suspend_collaborations(): confirm_write_access() from server.cron.collaboration_inactivity_suspension import suspend_collaborations return suspend_collaborations(current_app), 201
def do_expire_memberships(): confirm_write_access() from server.cron.membership_expiration import expire_memberships return expire_memberships(current_app), 201
def do_cleanup_non_open_requests(): confirm_write_access() from server.cron.cleanup_non_open_requests import cleanup_non_open_requests return cleanup_non_open_requests(current_app), 201
def do_outstanding_requests(): confirm_write_access() from server.cron.outstanding_requests import outstanding_requests return outstanding_requests(current_app), 200
def do_suspend_users(): confirm_write_access() from server.cron.user_suspending import suspend_users return suspend_users(current_app), 201