<commit_before>
# UUIDs in JSON files

All JSON configuration files must contain a [UUID (universally unique identifier)](https://en.wikipedia.org/wiki/Universally_unique_identifier) to link the on-disk JSON file to the corresponding object in the database. This looks like:

```json
{
    "uuid": "cef0cbf3-6458-4f13-a418-ee4d7e7505dd"
}
```

When you make new questions, assessments, etc, you will need to add a UUID to the the JSON file. These can be generated by [https://www.uuidgenerator.net](https://www.uuidgenerator.net) (the UUID version doesn't matter).


## When do you need a new UUID?

* **Renaming a directory: no new UUID needed.** For example if you rename a question or assessment directory, then you should leave the UUID the same, so that PrairieLearn will know that this is the same object but just with a new name.

* **Copying a directory: needs a new UUID.** For example, if you copy an existing question or assessment to make a new one, then you will need a new UUID for the new object, so that PrairieLearn can distinguish it from the original.

* **Moving a directory: needs a new UUID.** For example, if you move an assessment between course instances or if you move a question between courses, then you will need a new UUID for the object in its new location, so that PrairieLearn will know that this object should not be associated with the original.

If you copy questions or assessments from a different course and don't give them new UUIDs, then a local development copy of PrairieLearn running on your own machine may not be able to detect that you have not changed the UUIDs. This will only be detected when you sync your course to the production PrairieLearn server, at which point it will give an error.


## Bulk addition of UUIDs

To add a UUID to all the JSON files in a course you can run the included [`generate_uuids.py`](https://github.com/PrairieLearn/PrairieLearn/blob/master/tools/generate_uuids.py) Python script.

This script will add a UUID to the start of every JSON file that doesn't currently have one, so it's safe to run it multiple times. You will then need to commit and push these changes to GitHub.

To use the script, run:

```sh
cd <path_to_PrairieLearn>
cd tools
python generate_uuids.py <path_to_course_directory>
```

For example, `python generate_uuids.py ~/git/pl-tam212`.

If you're using the Docker container, you can avoid downloading the script by running:

```sh
docker run --rm -v /path/to/course:/course prairielearn/prairielearn python /PrairieLearn/tools/generate_uuids.py /course
```
<commit_msg>Improve notes on UUID changes<commit_after>
# UUIDs in JSON files

All JSON configuration files must contain a [UUID (universally unique identifier)](https://en.wikipedia.org/wiki/Universally_unique_identifier) to link the on-disk JSON file to the corresponding object in the database. This looks like:

```json
{
    "uuid": "cef0cbf3-6458-4f13-a418-ee4d7e7505dd"
}
```

When you make new questions, assessments, etc, you will need to add a UUID to the the JSON file. These can be generated by [https://www.uuidgenerator.net](https://www.uuidgenerator.net) (the UUID version doesn't matter).


## When do you need a new UUID?

As your course is constructed, you may run into scenarios that require you to change the UUID listed within a JSON file. Below, we've listed some common instances of when the UUID should or shouldn't be changed. 

* **Renaming a directory: no new UUID needed.** For example if you rename a question or assessment directory, then you should leave the UUID the same, so that PrairieLearn will know that this is the same object but just with a new name.

* **Copying a directory: needs a new UUID.** For example, if you copy an existing question or assessment to make a new one, then you will need a new UUID for the new object, so that PrairieLearn can distinguish it from the original.

* **Moving a directory: needs a new UUID.** For example, if you move an assessment between course instances or if you move a question between courses, then you will need a new UUID for the object in its new location, so that PrairieLearn will know that this object should not be associated with the original.

If you copy questions or assessments from a different course and don't give them new UUIDs, then a local development copy of PrairieLearn running on your own machine may not be able to detect that you have not changed the UUIDs. This will only be detected when you sync your course to the production PrairieLearn server, at which point it will give an error.

Furthermore, if you are adding a `TA` or `Instructor` to the `infoCourseInstance.json`, you do not need to change the UUID. Making a change to this file's UUID will create an _alternative_ version of course with the same name that lacks all assessment information previously held by the course. The original course can only be recovered by reverting the UUID change. If you have unintentionally stumbled into this scenario, you will likely be faced with a sync error of:

```
Error: UUID 0339b989-d1f2-4f96-bcba-8717c68a64a9 from assessment exam1 in Sp18 already in use in different course instance (possibly in a different course)
```

## Bulk addition of UUIDs

To add a UUID to all the JSON files in a course you can run the included [`generate_uuids.py`](https://github.com/PrairieLearn/PrairieLearn/blob/master/tools/generate_uuids.py) Python script.

This script will add a UUID to the start of every JSON file that doesn't currently have one, so it's safe to run it multiple times. You will then need to commit and push these changes to GitHub.

To use the script, run:

```sh
cd <path_to_PrairieLearn>
cd tools
python generate_uuids.py <path_to_course_directory>
```

For example, `python generate_uuids.py ~/git/pl-tam212`.

If you're using the Docker container, you can avoid downloading the script by running:

```sh
docker run --rm -v /path/to/course:/course prairielearn/prairielearn python /PrairieLearn/tools/generate_uuids.py /course
```

{'fraction_non_alphanumeric': 0.062229617304492515, 'fraction_numerical': 0.010981697171381031, 'mean_word_length': 4.449682683590209, 'pattern_counts': {'":': 2, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 8, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7074540', 'n_tokens_mistral': 1757, 'n_tokens_neox': 1612, 'n_words': 895}