tutor-contrib-sample 3.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tutor_contrib_sample-3.0.0.dist-info/METADATA +471 -0
- tutor_contrib_sample-3.0.0.dist-info/RECORD +7 -0
- tutor_contrib_sample-3.0.0.dist-info/WHEEL +5 -0
- tutor_contrib_sample-3.0.0.dist-info/entry_points.txt +2 -0
- tutor_contrib_sample-3.0.0.dist-info/top_level.txt +1 -0
- tutorsample/__init__.py +0 -0
- tutorsample/plugin.py +145 -0
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tutor-contrib-sample
|
|
3
|
+
Version: 3.0.0
|
|
4
|
+
Summary: Tutor plugin for the Open edX Sample Plugin
|
|
5
|
+
Author-email: Open edX Project <oscm@openedx.org>
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/openedx/sample-plugin
|
|
8
|
+
Project-URL: Repository, https://github.com/openedx/sample-plugin
|
|
9
|
+
Keywords: tutor,openedx,plugin
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Natural Language :: English
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Requires-Python: >=3.11
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
Requires-Dist: tutor>=17.0.0
|
|
18
|
+
|
|
19
|
+
# Tutor Plugin Configuration Guide
|
|
20
|
+
|
|
21
|
+
This directory contains Tutor plugin configuration for easy deployment of both backend and frontend plugins in a Tutor-based Open edX deployment.
|
|
22
|
+
|
|
23
|
+
## Table of Contents
|
|
24
|
+
|
|
25
|
+
- [Overview](#overview)
|
|
26
|
+
- [Plugin Configuration](#plugin-configuration)
|
|
27
|
+
- [Installation Steps](#installation-steps)
|
|
28
|
+
- [Development vs Production](#development-vs-production)
|
|
29
|
+
- [Configuration Options](#configuration-options)
|
|
30
|
+
- [Troubleshooting](#troubleshooting)
|
|
31
|
+
- [Advanced Configuration](#advanced-configuration)
|
|
32
|
+
|
|
33
|
+
## Overview
|
|
34
|
+
|
|
35
|
+
This Tutor plugin simplifies the deployment of the sample plugin by:
|
|
36
|
+
|
|
37
|
+
- **Backend Integration**: Automatically installs the Django app plugin
|
|
38
|
+
- **Frontend Integration**: Configures MFE slots for the custom components
|
|
39
|
+
- **Environment Setup**: Handles configuration across different deployment environments
|
|
40
|
+
- **Dependency Management**: Ensures all required packages are installed
|
|
41
|
+
|
|
42
|
+
**What is Tutor?**: Tutor is the official Docker-based deployment method for Open edX, providing simple commands for installation, configuration, and maintenance.
|
|
43
|
+
|
|
44
|
+
**Official Documentation:**
|
|
45
|
+
- [Tutor Documentation](https://docs.tutor.edly.io/)
|
|
46
|
+
- [Tutor Plugin Development](https://docs.tutor.edly.io/plugins/index.html)
|
|
47
|
+
|
|
48
|
+
## Plugin Configuration
|
|
49
|
+
|
|
50
|
+
**File**: [`sample.py`](./sample.py)
|
|
51
|
+
|
|
52
|
+
### Current Configuration
|
|
53
|
+
|
|
54
|
+
The current configuration demonstrates basic Tutor plugin structure:
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
from tutormfe.hooks import PLUGIN_SLOTS
|
|
58
|
+
|
|
59
|
+
PLUGIN_SLOTS.add_items([
|
|
60
|
+
# Replace the course_list
|
|
61
|
+
(
|
|
62
|
+
"learner-dashboard",
|
|
63
|
+
"custom_course_list",
|
|
64
|
+
"""
|
|
65
|
+
{
|
|
66
|
+
op: PLUGIN_OPERATIONS.Insert,
|
|
67
|
+
type: DIRECT_PLUGIN,
|
|
68
|
+
priority: 50,
|
|
69
|
+
RenderWidget: CourseList
|
|
70
|
+
}"""
|
|
71
|
+
),
|
|
72
|
+
])
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Note**: The current implementation is a basic template. For full functionality, this needs to be expanded with proper backend installation and frontend package management.
|
|
76
|
+
|
|
77
|
+
### Complete Plugin Structure
|
|
78
|
+
|
|
79
|
+
A fully functional Tutor plugin should include:
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
from tutor import hooks
|
|
83
|
+
|
|
84
|
+
# Plugin metadata
|
|
85
|
+
__version__ = "1.0.0"
|
|
86
|
+
|
|
87
|
+
# Backend plugin installation
|
|
88
|
+
@hooks.Filters.IMAGES_BUILD_MOUNTS.add()
|
|
89
|
+
def _mount_openedx_plugin_sample(mounts):
|
|
90
|
+
"""Mount the sample plugin source code for development."""
|
|
91
|
+
mounts.append(("sample-plugin-backend", "/openedx/sample-plugin-backend"))
|
|
92
|
+
return mounts
|
|
93
|
+
|
|
94
|
+
@hooks.Filters.LMS_ENV.add()
|
|
95
|
+
@hooks.Filters.CMS_ENV.add()
|
|
96
|
+
def _add_plugin_settings(env):
|
|
97
|
+
"""Add plugin-specific environment variables."""
|
|
98
|
+
env["SAMPLE_PLUGIN_ENABLED"] = True
|
|
99
|
+
return env
|
|
100
|
+
|
|
101
|
+
# Install backend plugin
|
|
102
|
+
@hooks.Filters.IMAGES_BUILD.add()
|
|
103
|
+
def _install_backend_plugin(build_config):
|
|
104
|
+
"""Install the backend plugin during image build."""
|
|
105
|
+
build_config.add_dockerfile_commands(
|
|
106
|
+
"RUN pip install -e /openedx/sample-plugin-backend"
|
|
107
|
+
)
|
|
108
|
+
return build_config
|
|
109
|
+
|
|
110
|
+
# Frontend plugin configuration
|
|
111
|
+
from tutormfe.hooks import PLUGIN_SLOTS
|
|
112
|
+
|
|
113
|
+
PLUGIN_SLOTS.add_items([
|
|
114
|
+
(
|
|
115
|
+
"learner-dashboard",
|
|
116
|
+
"course_list_slot",
|
|
117
|
+
"""
|
|
118
|
+
{
|
|
119
|
+
op: PLUGIN_OPERATIONS.Replace,
|
|
120
|
+
widget: {
|
|
121
|
+
id: 'custom_course_list',
|
|
122
|
+
type: DIRECT_PLUGIN,
|
|
123
|
+
priority: 50,
|
|
124
|
+
RenderWidget: CourseList
|
|
125
|
+
}
|
|
126
|
+
}"""
|
|
127
|
+
),
|
|
128
|
+
])
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Installation Steps
|
|
132
|
+
|
|
133
|
+
### Prerequisites
|
|
134
|
+
|
|
135
|
+
1. **Tutor Installation**: Follow [Tutor installation guide](https://docs.tutor.edly.io/install.html)
|
|
136
|
+
2. **Plugin Source**: Have the sample plugin source code available
|
|
137
|
+
3. **Tutor MFE Plugin**: Install tutor-mfe plugin if customizing frontend
|
|
138
|
+
|
|
139
|
+
### Step 1: Install Tutor Plugin
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
# Method 1: Install from local directory
|
|
143
|
+
pip install -e /path/to/sample-plugin/tutor-contrib-sample/
|
|
144
|
+
|
|
145
|
+
# Method 2: Copy plugin file (simpler for development)
|
|
146
|
+
mkdir -p "$(tutor plugins printroot)"
|
|
147
|
+
cp sample.py "$(tutor plugins printroot)/sample.py"
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Step 2: Enable Plugin
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
# Enable the plugin
|
|
154
|
+
tutor plugins enable sample
|
|
155
|
+
|
|
156
|
+
# Verify plugin is enabled
|
|
157
|
+
tutor plugins list
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Step 3: Deploy Backend Plugin
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
# For development deployment
|
|
164
|
+
tutor dev launch
|
|
165
|
+
|
|
166
|
+
# For production deployment
|
|
167
|
+
tutor local launch
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Step 4: Configure Frontend (if using MFE customization)
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
# If using tutor-mfe plugin for frontend customization
|
|
174
|
+
tutor plugins enable mfe
|
|
175
|
+
tutor local launch
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Step 5: Verify Installation
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
# Check backend plugin
|
|
182
|
+
tutor dev exec lms python manage.py shell -c "from openedx_plugin_sample.models import CourseArchiveStatus; print('Backend plugin loaded')"
|
|
183
|
+
|
|
184
|
+
# Check frontend plugin (visit learner dashboard in browser)
|
|
185
|
+
# Should see custom course list with archive functionality
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Development vs Production
|
|
189
|
+
|
|
190
|
+
### Development Mode
|
|
191
|
+
|
|
192
|
+
**Characteristics:**
|
|
193
|
+
- Uses `tutor dev` commands
|
|
194
|
+
- Mounts source code for live editing
|
|
195
|
+
- Faster iteration cycles
|
|
196
|
+
- Debug logging enabled
|
|
197
|
+
|
|
198
|
+
**Setup Pattern:**
|
|
199
|
+
```bash
|
|
200
|
+
# Mount backend plugin source
|
|
201
|
+
tutor dev mount /path/to/sample-plugin/backend:/openedx/sample-plugin-backend
|
|
202
|
+
|
|
203
|
+
# Start development environment
|
|
204
|
+
tutor dev launch
|
|
205
|
+
|
|
206
|
+
# Install plugin in development mode
|
|
207
|
+
tutor dev exec lms pip install -e ../sample-plugin-backend
|
|
208
|
+
tutor dev exec lms python manage.py migrate
|
|
209
|
+
tutor dev restart lms
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Production Mode
|
|
213
|
+
|
|
214
|
+
**Characteristics:**
|
|
215
|
+
- Uses `tutor local` commands
|
|
216
|
+
- Builds plugins into Docker images
|
|
217
|
+
- Optimized for performance
|
|
218
|
+
- Production logging levels
|
|
219
|
+
|
|
220
|
+
**Setup Pattern:**
|
|
221
|
+
```bash
|
|
222
|
+
# Enable plugin
|
|
223
|
+
tutor plugins enable sample
|
|
224
|
+
|
|
225
|
+
# Build and deploy
|
|
226
|
+
tutor local launch
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Key Differences
|
|
230
|
+
|
|
231
|
+
| Aspect | Development | Production |
|
|
232
|
+
|--------|-------------|------------|
|
|
233
|
+
| **Installation** | `pip install -e` (editable) | Built into image |
|
|
234
|
+
| **Code Changes** | Live reload | Requires rebuild |
|
|
235
|
+
| **Performance** | Slower (debug mode) | Optimized |
|
|
236
|
+
| **Database** | SQLite/development DB | Production database |
|
|
237
|
+
| **Logging** | Verbose | Production level |
|
|
238
|
+
|
|
239
|
+
## Configuration Options
|
|
240
|
+
|
|
241
|
+
### Backend Plugin Configuration
|
|
242
|
+
|
|
243
|
+
```python
|
|
244
|
+
# In tutor plugin
|
|
245
|
+
@hooks.Filters.LMS_ENV.add()
|
|
246
|
+
def _add_backend_settings(env):
|
|
247
|
+
"""Configure backend plugin settings."""
|
|
248
|
+
env.update({
|
|
249
|
+
# Plugin-specific settings
|
|
250
|
+
"SAMPLE_PLUGIN_API_RATE_LIMIT": "100/minute",
|
|
251
|
+
"SAMPLE_PLUGIN_ARCHIVE_RETENTION": "365",
|
|
252
|
+
|
|
253
|
+
# Open edX Filters configuration
|
|
254
|
+
"OPEN_EDX_FILTERS_CONFIG": {
|
|
255
|
+
"org.openedx.learning.course.about.render.started.v1": {
|
|
256
|
+
"pipeline": [
|
|
257
|
+
"openedx_plugin_sample.pipeline.ChangeCourseAboutPageUrl"
|
|
258
|
+
],
|
|
259
|
+
"fail_silently": False,
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
})
|
|
263
|
+
return env
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### Frontend Plugin Configuration
|
|
267
|
+
|
|
268
|
+
```python
|
|
269
|
+
# Configure MFE slots
|
|
270
|
+
PLUGIN_SLOTS.add_items([
|
|
271
|
+
(
|
|
272
|
+
"learner-dashboard", # Target MFE
|
|
273
|
+
"course_list_slot", # Slot identifier
|
|
274
|
+
"""
|
|
275
|
+
{
|
|
276
|
+
op: PLUGIN_OPERATIONS.Replace, // Operation type
|
|
277
|
+
widget: {
|
|
278
|
+
id: 'custom_course_list', // Unique widget ID
|
|
279
|
+
type: DIRECT_PLUGIN, // Plugin type
|
|
280
|
+
priority: 50, // Load priority
|
|
281
|
+
RenderWidget: CourseList // Component reference
|
|
282
|
+
}
|
|
283
|
+
}"""
|
|
284
|
+
),
|
|
285
|
+
])
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Environment-Specific Configuration
|
|
289
|
+
|
|
290
|
+
```python
|
|
291
|
+
# Different settings for different environments
|
|
292
|
+
@hooks.Filters.LMS_ENV.add()
|
|
293
|
+
def _configure_by_environment(env):
|
|
294
|
+
"""Apply environment-specific configuration."""
|
|
295
|
+
if env.get("TUTOR_DEV", False):
|
|
296
|
+
# Development settings
|
|
297
|
+
env["SAMPLE_PLUGIN_DEBUG"] = True
|
|
298
|
+
env["SAMPLE_PLUGIN_API_RATE_LIMIT"] = "1000/minute"
|
|
299
|
+
else:
|
|
300
|
+
# Production settings
|
|
301
|
+
env["SAMPLE_PLUGIN_DEBUG"] = False
|
|
302
|
+
env["SAMPLE_PLUGIN_API_RATE_LIMIT"] = "60/minute"
|
|
303
|
+
|
|
304
|
+
return env
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
## Troubleshooting
|
|
308
|
+
|
|
309
|
+
### Common Issues
|
|
310
|
+
|
|
311
|
+
**Plugin Not Loading:**
|
|
312
|
+
```bash
|
|
313
|
+
# Check if plugin is enabled
|
|
314
|
+
tutor plugins list
|
|
315
|
+
|
|
316
|
+
# Check plugin syntax
|
|
317
|
+
python -m py_compile sample.py
|
|
318
|
+
|
|
319
|
+
# Verify plugin location
|
|
320
|
+
tutor plugins printroot
|
|
321
|
+
ls -la "$(tutor plugins printroot)/"
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
**Backend Plugin Not Installing:**
|
|
325
|
+
```bash
|
|
326
|
+
# Check build logs
|
|
327
|
+
tutor images build lms
|
|
328
|
+
|
|
329
|
+
# Manual installation for debugging
|
|
330
|
+
tutor dev exec lms pip install -e ../sample-plugin-backend
|
|
331
|
+
tutor dev exec lms python -c "import openedx_plugin_sample; print('Success')"
|
|
332
|
+
|
|
333
|
+
# Check migrations
|
|
334
|
+
tutor dev exec lms python manage.py showmigrations openedx_plugin_sample
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
**Frontend Plugin Not Appearing:**
|
|
338
|
+
```bash
|
|
339
|
+
# Check MFE configuration
|
|
340
|
+
tutor dev exec learner-dashboard env | grep PLUGIN
|
|
341
|
+
|
|
342
|
+
# Verify plugin slots
|
|
343
|
+
tutor dev logs learner-dashboard
|
|
344
|
+
|
|
345
|
+
# Check browser console for JavaScript errors
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
**Settings Not Applied:**
|
|
349
|
+
```bash
|
|
350
|
+
# Check environment variables
|
|
351
|
+
tutor dev exec lms env | grep SAMPLE_PLUGIN
|
|
352
|
+
|
|
353
|
+
# Verify Django settings
|
|
354
|
+
tutor dev exec lms python manage.py shell -c "from django.conf import settings; print(getattr(settings, 'SAMPLE_PLUGIN_DEBUG', 'Not set'))"
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### Debug Commands
|
|
358
|
+
|
|
359
|
+
```bash
|
|
360
|
+
# View plugin configuration
|
|
361
|
+
tutor plugins show sample
|
|
362
|
+
|
|
363
|
+
# Check generated configuration
|
|
364
|
+
tutor config printvalue PLUGINS
|
|
365
|
+
|
|
366
|
+
# Inspect environment variables
|
|
367
|
+
tutor dev exec lms env | grep -E "(SAMPLE_PLUGIN|OPEN_EDX)"
|
|
368
|
+
|
|
369
|
+
# Check plugin installation
|
|
370
|
+
tutor dev exec lms pip list | grep sample
|
|
371
|
+
|
|
372
|
+
# View logs
|
|
373
|
+
tutor dev logs lms
|
|
374
|
+
tutor dev logs learner-dashboard
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
### Getting Help
|
|
378
|
+
|
|
379
|
+
1. **Tutor Documentation**: [Plugin Development Guide](https://docs.tutor.edly.io/plugins/intro.html)
|
|
380
|
+
2. **Community**: [Tutor Community Forum](https://discuss.openedx.org/c/ops-and-deployment/tutor/)
|
|
381
|
+
3. **GitHub**: [Tutor Repository Issues](https://github.com/overhangio/tutor/issues)
|
|
382
|
+
|
|
383
|
+
## Advanced Configuration
|
|
384
|
+
|
|
385
|
+
### Multi-MFE Plugin Configuration
|
|
386
|
+
|
|
387
|
+
```python
|
|
388
|
+
# Configure multiple MFEs
|
|
389
|
+
PLUGIN_SLOTS.add_items([
|
|
390
|
+
# Learner Dashboard
|
|
391
|
+
(
|
|
392
|
+
"learner-dashboard",
|
|
393
|
+
"course_list_slot",
|
|
394
|
+
"""{ /* CourseList configuration */ }"""
|
|
395
|
+
),
|
|
396
|
+
|
|
397
|
+
# Course Authoring (if applicable)
|
|
398
|
+
(
|
|
399
|
+
"course-authoring",
|
|
400
|
+
"course_outline_slot",
|
|
401
|
+
"""{ /* Course outline customization */ }"""
|
|
402
|
+
),
|
|
403
|
+
])
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
### Custom Image Building
|
|
407
|
+
|
|
408
|
+
```python
|
|
409
|
+
@hooks.Filters.IMAGES_BUILD.add()
|
|
410
|
+
def _build_custom_image(build_config):
|
|
411
|
+
"""Build custom image with additional dependencies."""
|
|
412
|
+
|
|
413
|
+
# Add system packages
|
|
414
|
+
build_config.add_dockerfile_commands(
|
|
415
|
+
"RUN apt-get update && apt-get install -y your-package"
|
|
416
|
+
)
|
|
417
|
+
|
|
418
|
+
# Install Python packages
|
|
419
|
+
build_config.add_dockerfile_commands(
|
|
420
|
+
"RUN pip install your-python-package"
|
|
421
|
+
)
|
|
422
|
+
|
|
423
|
+
# Copy additional files
|
|
424
|
+
build_config.add_dockerfile_commands(
|
|
425
|
+
"COPY custom-config.yml /openedx/config/"
|
|
426
|
+
)
|
|
427
|
+
|
|
428
|
+
return build_config
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
### Database Migrations
|
|
432
|
+
|
|
433
|
+
```python
|
|
434
|
+
@hooks.Actions.LMS_READY.add()
|
|
435
|
+
@hooks.Actions.CMS_READY.add()
|
|
436
|
+
def _run_plugin_migrations():
|
|
437
|
+
"""Run plugin migrations when platform is ready."""
|
|
438
|
+
from django.core.management import call_command
|
|
439
|
+
call_command("migrate", "openedx_plugin_sample")
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
### Plugin Dependencies
|
|
443
|
+
|
|
444
|
+
```python
|
|
445
|
+
# In setup.py or pyproject.toml for your Tutor plugin
|
|
446
|
+
dependencies = [
|
|
447
|
+
"tutor>=15.0.0",
|
|
448
|
+
"tutor-mfe", # If using MFE customization
|
|
449
|
+
]
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
### Environment Validation
|
|
453
|
+
|
|
454
|
+
```python
|
|
455
|
+
@hooks.Filters.CONFIG_UNIQUE.add()
|
|
456
|
+
def _validate_plugin_config(config):
|
|
457
|
+
"""Validate plugin configuration."""
|
|
458
|
+
|
|
459
|
+
# Check required settings
|
|
460
|
+
if not config.get("SAMPLE_PLUGIN_API_KEY"):
|
|
461
|
+
raise ValueError("SAMPLE_PLUGIN_API_KEY is required")
|
|
462
|
+
|
|
463
|
+
# Validate setting values
|
|
464
|
+
rate_limit = config.get("SAMPLE_PLUGIN_API_RATE_LIMIT", "60/minute")
|
|
465
|
+
if not re.match(r"^\d+/(minute|hour|day)$", rate_limit):
|
|
466
|
+
raise ValueError(f"Invalid rate limit format: {rate_limit}")
|
|
467
|
+
|
|
468
|
+
return config
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
This Tutor plugin configuration provides a foundation for deploying the sample plugin in production Open edX environments. The modular approach allows you to adapt the configuration for different deployment scenarios while maintaining consistency across environments.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
tutorsample/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
tutorsample/plugin.py,sha256=tNSrxs_c8Rr3dKM2VGZD4TKAA24mMaeFCQSErFnPhBo,5658
|
|
3
|
+
tutor_contrib_sample-3.0.0.dist-info/METADATA,sha256=gbFzdSHatnkmoYrYPRvi_JAUu9L-E7YU2ljKn0Cbw9w,12544
|
|
4
|
+
tutor_contrib_sample-3.0.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
5
|
+
tutor_contrib_sample-3.0.0.dist-info/entry_points.txt,sha256=mUycO_xVAnI9etLsiJcR3gwHQm3aS-5sfdez-6Senrk,46
|
|
6
|
+
tutor_contrib_sample-3.0.0.dist-info/top_level.txt,sha256=e_6Du9imVs8zQJlt9HDhkBJ9Ld70gDv4_we7o1VuRIg,12
|
|
7
|
+
tutor_contrib_sample-3.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
tutorsample
|
tutorsample/__init__.py
ADDED
|
File without changes
|
tutorsample/plugin.py
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tutor plugin for the Open edX Sample Plugin.
|
|
3
|
+
|
|
4
|
+
Installs the backend Django app (openedx-plugin-sample from PyPI) into LMS/CMS
|
|
5
|
+
and configures the frontend MFE slot (from @openedx/plugin-sample on npm) in the
|
|
6
|
+
learner-dashboard.
|
|
7
|
+
|
|
8
|
+
Requirements:
|
|
9
|
+
tutor>=17.0.0
|
|
10
|
+
tutor-mfe (for frontend slot configuration)
|
|
11
|
+
"""
|
|
12
|
+
import json
|
|
13
|
+
|
|
14
|
+
from tutor import hooks
|
|
15
|
+
|
|
16
|
+
try:
|
|
17
|
+
from tutormfe.hooks import PLUGIN_SLOTS
|
|
18
|
+
_tutormfe_available = True
|
|
19
|
+
except ImportError:
|
|
20
|
+
_tutormfe_available = False
|
|
21
|
+
|
|
22
|
+
# ---------------------------------------------------------------------------
|
|
23
|
+
# Backend: Install the Django app plugin into LMS and CMS images
|
|
24
|
+
# ---------------------------------------------------------------------------
|
|
25
|
+
|
|
26
|
+
# The openedx-dockerfile-post-python-requirements patch runs after pip
|
|
27
|
+
# installs the base Open edX requirements. Plugins installed here are
|
|
28
|
+
# available in both LMS and CMS containers.
|
|
29
|
+
|
|
30
|
+
# @@TODO: reinstate once published
|
|
31
|
+
#hooks.Filters.ENV_PATCHES.add_item((
|
|
32
|
+
# "openedx-dockerfile-post-python-requirements",
|
|
33
|
+
# "RUN pip install openedx-plugin-sample",
|
|
34
|
+
#))
|
|
35
|
+
|
|
36
|
+
# Ensure that *if* backend-plugin-sample is bind-mounted, then it is mapped
|
|
37
|
+
# to /mnt/backend-plugin-sample and pip-installed as part of the openedx
|
|
38
|
+
# and openedx-dev image builds
|
|
39
|
+
|
|
40
|
+
hooks.Filters.MOUNTED_DIRECTORIES.add_item(("openedx", "backend-plugin-sample"))
|
|
41
|
+
|
|
42
|
+
# ---------------------------------------------------------------------------
|
|
43
|
+
# Migrations: Run openedx_plugin_sample migrations on init
|
|
44
|
+
# ---------------------------------------------------------------------------
|
|
45
|
+
|
|
46
|
+
hooks.Filters.CLI_DO_INIT_TASKS.add_item((
|
|
47
|
+
"lms",
|
|
48
|
+
"./manage.py lms migrate openedx_plugin_sample",
|
|
49
|
+
))
|
|
50
|
+
hooks.Filters.CLI_DO_INIT_TASKS.add_item((
|
|
51
|
+
"cms",
|
|
52
|
+
"./manage.py cms migrate openedx_plugin_sample",
|
|
53
|
+
))
|
|
54
|
+
|
|
55
|
+
# ---------------------------------------------------------------------------
|
|
56
|
+
# Frontend: Install npm package and configure the learner-dashboard slot
|
|
57
|
+
# ---------------------------------------------------------------------------
|
|
58
|
+
# Only runs when tutor-mfe is installed, so the plugin degrades gracefully
|
|
59
|
+
# if someone uses this plugin without the MFE plugin.
|
|
60
|
+
# ---------------------------------------------------------------------------
|
|
61
|
+
|
|
62
|
+
if _tutormfe_available:
|
|
63
|
+
# Step 1: Install the npm package into all MFE images.
|
|
64
|
+
# Ideally this would use mfe-dockerfile-post-npm-install-learner-dashboard
|
|
65
|
+
# to scope installation to only the MFE that needs it, but env.config.jsx
|
|
66
|
+
# is a single shared file rendered for all MFEs. The buildtime import below
|
|
67
|
+
# must resolve in every MFE's node_modules, so we install it globally.
|
|
68
|
+
# The plugin slot config is still scoped to learner-dashboard at runtime.
|
|
69
|
+
hooks.Filters.ENV_PATCHES.add_item((
|
|
70
|
+
"mfe-dockerfile-post-npm-install",
|
|
71
|
+
"RUN npm install @openedx/plugin-sample",
|
|
72
|
+
))
|
|
73
|
+
|
|
74
|
+
# Step 2: Import the CourseList component in the MFE env config so it is
|
|
75
|
+
# in scope when the plugin slot configuration is evaluated at runtime.
|
|
76
|
+
# The mfe-env-config-buildtime-imports patch injects import statements
|
|
77
|
+
# into the generated env.config.jsx file.
|
|
78
|
+
hooks.Filters.ENV_PATCHES.add_item((
|
|
79
|
+
"mfe-env-config-buildtime-imports",
|
|
80
|
+
"import { CourseList } from '@openedx/plugin-sample';",
|
|
81
|
+
))
|
|
82
|
+
|
|
83
|
+
# Step 3: Configure the course list plugin slot.
|
|
84
|
+
# - Hide the default CourseList that ships with the learner-dashboard.
|
|
85
|
+
# - Insert our custom CourseList that adds archive/unarchive functionality.
|
|
86
|
+
#
|
|
87
|
+
# Slot ID: org.openedx.frontend.learner_dashboard.course_list.v1
|
|
88
|
+
# Props passed by the slot: courseListData (visibleList, numPages,
|
|
89
|
+
# setPageNumber, filterOptions, showFilters)
|
|
90
|
+
PLUGIN_SLOTS.add_item((
|
|
91
|
+
"learner-dashboard",
|
|
92
|
+
"org.openedx.frontend.learner_dashboard.course_list.v1",
|
|
93
|
+
"""
|
|
94
|
+
{
|
|
95
|
+
op: PLUGIN_OPERATIONS.Hide,
|
|
96
|
+
widgetId: 'default_contents',
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
op: PLUGIN_OPERATIONS.Insert,
|
|
100
|
+
widget: {
|
|
101
|
+
id: 'openedx_plugin_sample_course_list',
|
|
102
|
+
type: DIRECT_PLUGIN,
|
|
103
|
+
priority: 50,
|
|
104
|
+
RenderWidget: CourseList,
|
|
105
|
+
},
|
|
106
|
+
}""",
|
|
107
|
+
))
|
|
108
|
+
|
|
109
|
+
# ---------------------------------------------------------------------------
|
|
110
|
+
# Brand: Override Paragon theme CSS with brand-sample
|
|
111
|
+
# ---------------------------------------------------------------------------
|
|
112
|
+
# Open edX MFEs load their Paragon design-system CSS at runtime via the
|
|
113
|
+
# PARAGON_THEME_URLS setting. The "default" URL points at upstream Paragon;
|
|
114
|
+
# the optional "brandOverride" URL is loaded on top to recolor/restyle the
|
|
115
|
+
# theme. We point brandOverride at the compiled CSS in this repo's
|
|
116
|
+
# brand-sample/ directory, served via jsDelivr straight from GitHub.
|
|
117
|
+
#
|
|
118
|
+
# TODO: This assumes brand-sample has been pushed to jsdelivr.
|
|
119
|
+
# Is it possible to set this up for dev so that it loads the brand from
|
|
120
|
+
# the filesystem instead?
|
|
121
|
+
# ANSWER: Yes, it is possible using the tutor-contrib-paragon plugin.
|
|
122
|
+
# We should update this section to use that.
|
|
123
|
+
# ---------------------------------------------------------------------------
|
|
124
|
+
|
|
125
|
+
paragon_theme_urls = {
|
|
126
|
+
"variants": {
|
|
127
|
+
"light": {
|
|
128
|
+
"urls": {
|
|
129
|
+
"default": "https://cdn.jsdelivr.net/npm/@openedx/paragon@$paragonVersion/dist/light.min.css",
|
|
130
|
+
"brandOverride": "https://cdn.jsdelivr.net/gh/openedx/sample-plugin@main/brand-sample/dist/light.min.css"
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
brand_settings_lines = f"""
|
|
137
|
+
MFE_CONFIG["PARAGON_THEME_URLS"] = {json.dumps(paragon_theme_urls)}
|
|
138
|
+
"""
|
|
139
|
+
|
|
140
|
+
hooks.Filters.ENV_PATCHES.add_item(
|
|
141
|
+
(
|
|
142
|
+
"mfe-lms-common-settings",
|
|
143
|
+
brand_settings_lines,
|
|
144
|
+
)
|
|
145
|
+
)
|