|
1 | 1 | import logging |
2 | 2 |
|
3 | | -from django.contrib import admin |
| 3 | +from django.contrib import admin, messages |
4 | 4 | from django.contrib.auth import admin as auth_admin |
5 | 5 | from django import forms |
6 | 6 | from lib.fields import LdapCsvField |
|
10 | 10 | CuLdapUser, |
11 | 11 | RcLdapGroup, |
12 | 12 | IdTracker, |
| 13 | + ComanageUser, |
| 14 | + ComanageGroup, |
13 | 15 | AccountRequest, |
14 | 16 | Intent, |
15 | 17 | ORGANIZATIONS |
16 | 18 | ) |
| 19 | +from django.urls import reverse_lazy |
| 20 | +from django.shortcuts import render |
| 21 | +from .forms import ComanageSyncForm |
| 22 | +from .models import ComanageUser |
| 23 | +from comanage.lib import UserCO |
| 24 | +from lib.utils import get_user_and_groups, get_comanage_users_by_org |
| 25 | +from django.urls import path |
| 26 | +from django.utils.html import format_html |
| 27 | +from django.urls import reverse |
| 28 | +from django.shortcuts import redirect |
| 29 | +from django.http import HttpResponseRedirect |
| 30 | +from django.db.models import Q |
17 | 31 |
|
18 | 32 |
|
19 | 33 | @admin.register(User) |
@@ -204,4 +218,267 @@ class RcLdapGroupAdmin(RcLdapModelAdmin): |
204 | 218 | search_fields = ['name'] |
205 | 219 | form = RcLdapGroupForm |
206 | 220 |
|
| 221 | +# Custom action to sync users from Comanage |
| 222 | +def sync_users_from_comanage(modeladmin, request, queryset): |
| 223 | + """ |
| 224 | + Sync the selected users from Comanage. |
| 225 | + """ |
| 226 | + if not queryset: |
| 227 | + users = ["kyre0001_amc"] |
| 228 | + for user in users: |
| 229 | + # try: |
| 230 | + # ComanageUser.sync_from_comanage(user.user_id) # Call the sync method on the user |
| 231 | + # modeladmin.message_user(request, f"User {user.name} synced successfully!") |
| 232 | + # except Exception as e: |
| 233 | + # modeladmin.message_user(request, f"Error syncing user {user.name}: {str(e)}", level='debug') |
| 234 | + try: |
| 235 | + ComanageUser.sync_from_comanage(user) # Call the sync method on the user |
| 236 | + modeladmin.message_user(request, f"User {user} synced successfully!") |
| 237 | + except Exception as e: |
| 238 | + modeladmin.message_user(request, f"Error syncing user {user}: {str(e)}", level='debug') |
| 239 | + |
| 240 | +# Action to sync users in bulk |
| 241 | +def sync_users_from_comanage(modeladmin, request, queryset): |
| 242 | + """ |
| 243 | + Sync the selected users from Comanage. |
| 244 | + """ |
| 245 | + if queryset.count() == 0: |
| 246 | + modeladmin.message_user(request, "No users selected to sync.", level=messages.WARNING) |
| 247 | + return |
| 248 | + |
| 249 | + for user in queryset: |
| 250 | + try: |
| 251 | + # Assuming ComanageUser.sync_from_comanage expects user ID |
| 252 | + ComanageUser.sync_from_comanage(user.user_id) # Sync logic here |
| 253 | + modeladmin.message_user(request, f"User {user.name} synced successfully!", level=messages.SUCCESS) |
| 254 | + except Exception as e: |
| 255 | + modeladmin.message_user(request, f"Error syncing user {user.name}: {str(e)}", level=messages.ERROR) |
| 256 | + |
| 257 | +# ComanageUserAdmin with additional customization and sync functionality |
| 258 | +class ComanageUserAdmin(admin.ModelAdmin): |
| 259 | + list_display = ['user_id', 'name', 'email', 'co_person_id'] |
| 260 | + search_fields = ['user_id', 'name', 'email', 'co_person_id'] |
| 261 | + readonly_fields = ['user_id', 'name', 'email', 'co_person_id', 'group_names', 'created_at', 'modified'] |
| 262 | + actions = [sync_users_from_comanage] |
| 263 | + |
| 264 | + # Disable the "Add" button in the list view |
| 265 | + def has_add_permission(self, request): |
| 266 | + return False |
| 267 | + |
| 268 | + # Disable the delete button for individual objects |
| 269 | + def has_delete_permission(self, request, obj=None): |
| 270 | + return False |
| 271 | + |
| 272 | + def changelist_view(self, request, extra_context=None): |
| 273 | + """ |
| 274 | + Override the changelist view to trigger a function when the list of users is accessed. |
| 275 | + """ |
| 276 | + # Call your custom function here (e.g., sync users from Comanage) |
| 277 | + try: |
| 278 | + user = "kyre0001_amc" # Or you can filter users as needed |
| 279 | + ComanageUser.sync_from_comanage(user) # Call your sync function here |
| 280 | + self.message_user(request, "Users synced successfully!", level=messages.SUCCESS) |
| 281 | + except Exception as e: |
| 282 | + self.message_user(request, f"Error syncing users: {str(e)}", level=messages.ERROR) |
| 283 | + |
| 284 | + # Proceed with the normal changelist view rendering |
| 285 | + return super().changelist_view(request, extra_context) |
| 286 | + |
| 287 | + # Override the change_view method to remove the "Save" button and show custom sync button |
| 288 | + def change_view(self, request, object_id, form_url='', extra_context=None): |
| 289 | + extra_context = extra_context or {} |
| 290 | + extra_context['show_save_and_add_another'] = False |
| 291 | + extra_context['show_save_and_continue'] = False |
| 292 | + extra_context['show_save'] = False |
| 293 | + |
| 294 | + return super().change_view(request, object_id, form_url, extra_context) |
| 295 | + |
| 296 | +# class ComanageUserAdmin(admin.ModelAdmin): |
| 297 | +# list_display = ['user_id', 'name', 'email', 'co_person_id'] |
| 298 | +# search_fields = ['user_id', 'name', 'email', 'co_person_id'] |
| 299 | +# readonly_fields = ['user_id', 'name', 'email', 'co_person_id', 'group_names', 'created_at', 'modified',] |
| 300 | +# actions = [sync_users_from_comanage] |
| 301 | + |
| 302 | +# # Disable the "Add" button in the list view |
| 303 | +# def has_add_permission(self, request): |
| 304 | +# return False |
| 305 | + |
| 306 | +# # Disable the delete button for individual objects |
| 307 | +# def has_delete_permission(self, request, obj=None): |
| 308 | +# return False |
| 309 | + |
| 310 | +# # Override the change_view method to remove the "Save" button |
| 311 | +# def change_view(self, request, object_id, form_url='', extra_context=None): |
| 312 | +# extra_context = extra_context or {} |
| 313 | +# extra_context['show_save_and_add_another'] = False |
| 314 | +# extra_context['show_save_and_continue'] = False |
| 315 | +# extra_context['show_save'] = False |
| 316 | +# return super().change_view(request, object_id, form_url, extra_context) |
| 317 | + |
| 318 | + # Optionally, you can define a custom form (not shown here) |
| 319 | + # form = CustomUserForm # Uncomment and define your form if necessary |
| 320 | + |
| 321 | +# class ComanageSyncAdmin(admin.ModelAdmin): |
| 322 | +# change_list_template = "comanage_sync_list.html" # Custom template for the changelist page |
| 323 | +# list_display = ('user_id', 'name', 'email', 'created_at', 'modified', 'actions') |
| 324 | +# search_fields = ['user_id', 'name', 'email'] |
| 325 | +# actions = ['custom_action'] |
| 326 | + |
| 327 | +# def changelist_view(self, request, extra_context=None): |
| 328 | +# search_query = request.GET.get('q', '') |
| 329 | + |
| 330 | +# # Filter user data if there is a search query |
| 331 | +# if search_query: |
| 332 | +# user_data = ComanageUser.objects.filter( |
| 333 | +# Q(user_id__icontains=search_query) | Q(email__icontains=search_query) |
| 334 | +# ) |
| 335 | +# else: |
| 336 | +# # Fetch all user data if no search query is provided |
| 337 | +# user_data = ComanageUser.objects.all() |
| 338 | + |
| 339 | +# # Add user data to the context for rendering |
| 340 | +# extra_context = extra_context or {} |
| 341 | +# extra_context['user_data'] = user_data |
| 342 | +# extra_context['search_query'] = search_query # Optional: to display the query in the search bar |
| 343 | + |
| 344 | +# # Render the custom changelist view with the extra context |
| 345 | +# return super().changelist_view(request, extra_context=extra_context) |
| 346 | + |
| 347 | +# # Define custom URL for detailed group view |
| 348 | +# def get_urls(self): |
| 349 | +# # Get default admin URLs |
| 350 | +# urls = super().get_urls() |
| 351 | + |
| 352 | +# # Add custom URL for sync users and user detail view |
| 353 | +# custom_urls = [ |
| 354 | +# path('sync-users/', self.admin_site.admin_view(self.sync_multiple_users), name='comanage-sync-users'), |
| 355 | +# path('comanage-sync/<str:user_id>/view-groups/', self.admin_site.admin_view(self.view_groups), name='comanage-sync-view-groups'), |
| 356 | +# path('comanage-sync/<str:user_id>/', self.admin_site.admin_view(self.comanage_sync_view), name='comanage-sync-user-detail'), |
| 357 | +# ] |
| 358 | +# return custom_urls + urls |
| 359 | + |
| 360 | +# # View to show detailed user info and groups |
| 361 | +# def comanage_sync_view(self, request, user_id): |
| 362 | +# # Fetch user and group data based on user_id |
| 363 | +# user_data, groups = get_user_and_groups(user_id) # You need to implement this function |
| 364 | + |
| 365 | +# # Render the user detail page with user data and groups |
| 366 | +# return render(request, 'comanage_sync_detail.html', { |
| 367 | +# 'user_data': user_data, |
| 368 | +# 'groups': groups, |
| 369 | +# }) |
| 370 | + |
| 371 | +# # Function to handle syncing multiple users |
| 372 | +# def sync_multiple_users(self, request): |
| 373 | +# # Define your list of user_ids to sync |
| 374 | + |
| 375 | +# user_data = get_comanage_users_by_org() |
| 376 | + |
| 377 | +# # Sync users from Comanage |
| 378 | +# for user in user_data: |
| 379 | +# ComanageUser.sync_from_comanage(user.cuhpcuid) # Sync method for updating users |
| 380 | + |
| 381 | +# # Redirect back to the changelist view after sync is complete |
| 382 | +# self.message_user(request, "Users have been synced successfully!") |
| 383 | +# url = reverse('admin:accounts_comanageuser_changelist') |
| 384 | + |
| 385 | +# return redirect(url) # Update this URL if necessary |
| 386 | + |
| 387 | +# # Add actions to your admin class to display a custom button |
| 388 | +# def changelist_actions(self, request): |
| 389 | +# # Custom button that will trigger the sync function |
| 390 | +# return format_html('<a class="button" href="{}">Sync Users</a>', |
| 391 | +# self.admin_site.urls['comanage-sync-users'] |
| 392 | +# ) |
| 393 | + |
| 394 | +# def custom_action(self, obj): |
| 395 | +# # Add "View Groups" link for each user |
| 396 | +# return format_html('<a href="{}" class="button">View Groups</a>', |
| 397 | +# reverse('admin:comanage-sync-user-detail', args=[obj.user_id]) |
| 398 | +# ) |
| 399 | + |
| 400 | +# def view_groups(self, request, user_id): |
| 401 | +# try: |
| 402 | +# # Fetch the user based on user_id |
| 403 | +# user = ComanageUser.objects.get(user_id=user_id) |
| 404 | + |
| 405 | +# # Fetch the user's groups, assuming you have a `groups` field or relation in your model |
| 406 | +# user_groups = user.groups.all() |
| 407 | + |
| 408 | +# # Get members of each group (assuming there's a Many-to-Many or ForeignKey relationship with users) |
| 409 | +# group_members = {} |
| 410 | +# for group in user_groups: |
| 411 | +# group_members[group.name] = group.members.all() # Adjust based on your Group model |
| 412 | + |
| 413 | +# return render(request, 'view_groups.html', { |
| 414 | +# 'user': user, |
| 415 | +# 'user_groups': user_groups, |
| 416 | +# 'group_members': group_members, |
| 417 | +# }) |
| 418 | + |
| 419 | +# except ComanageUser.DoesNotExist: |
| 420 | +# raise Http404("User not found") |
| 421 | + |
| 422 | +class ComanageGroupForm(forms.ModelForm): |
| 423 | + def __init__(self, *args, **kwargs): |
| 424 | + super(ComanageGroupForm, self).__init__(*args, **kwargs) |
| 425 | + instance = getattr(self, 'instance', None) |
| 426 | + group_members = None |
| 427 | + |
| 428 | + if instance and instance.pk: |
| 429 | + # If the group instance exists, filter out the members already in the group |
| 430 | + group_members = instance.members.all() |
| 431 | + available_users = ComanageUser.objects.all() |
| 432 | + else: |
| 433 | + # If this is a new group, show all users |
| 434 | + available_users = ComanageUser.objects.all() |
| 435 | + |
| 436 | + # Prepare choices for the 'members' field (users not already in the group) |
| 437 | + user_choices = [ |
| 438 | + (user.id, f'{user.name} ({user.user_id})') for user in available_users |
| 439 | + ] |
| 440 | + |
| 441 | + # Set pre-selected members based on the group instance |
| 442 | + self.fields['members'].initial = group_members |
| 443 | + |
| 444 | + # Set the required fields |
| 445 | + self.fields['gid'].required = False |
| 446 | + self.fields['members'].required = False |
| 447 | + |
| 448 | + # Apply the filtered multi-select widget |
| 449 | + self.fields['members'].widget = admin.widgets.FilteredSelectMultiple( |
| 450 | + verbose_name='Members', |
| 451 | + is_stacked=False |
| 452 | + ) |
| 453 | + |
| 454 | + # Assign the available choices dynamically |
| 455 | + self.fields['members'].choices = user_choices |
| 456 | + |
| 457 | + class Meta: |
| 458 | + model = ComanageGroup |
| 459 | + fields = ['name', 'group_id', 'gid', 'created_at', 'modified', 'members'] |
| 460 | + |
| 461 | +class ComanageGroupAdmin(admin.ModelAdmin): |
| 462 | + list_display = ['name', 'gid', 'get_members'] |
| 463 | + search_fields = ['name', 'group_id', 'gid'] |
| 464 | + readonly_fields = ['group_id', 'created_at', 'modified'] |
| 465 | + form = ComanageGroupForm |
| 466 | + |
| 467 | + # Custom method to display group members |
| 468 | + def get_members(self, obj): |
| 469 | + """ |
| 470 | + Custom method to display all members of the group in the admin list view. |
| 471 | + """ |
| 472 | + return ", ".join([user.name for user in obj.members.all()]) |
| 473 | + |
| 474 | + get_members.short_description = 'Group Members' |
| 475 | + |
| 476 | + def get_queryset(self, request): |
| 477 | + queryset = super().get_queryset(request) |
| 478 | + # Optionally, modify the queryset if needed |
| 479 | + return queryset |
| 480 | + |
| 481 | +admin.site.register(ComanageGroup, ComanageGroupAdmin) |
| 482 | +admin.site.register(ComanageUser, ComanageUserAdmin) |
| 483 | + |
207 | 484 | admin.site.register(IdTracker) |
0 commit comments