-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
551c8e8
commit 4bc31ef
Showing
11 changed files
with
369 additions
and
100 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import os | ||
from defines import auth_headers | ||
from appointment.database import repo | ||
|
||
|
||
class TestInvite: | ||
def test_send_invite_email_requires_admin(self, with_db, with_client): | ||
"""Ensures send_invite_email requires an admin user""" | ||
|
||
os.environ['APP_ADMIN_ALLOW_LIST'] = '@notexample.org' | ||
|
||
response = with_client.post( | ||
"/invite/send", | ||
json={ | ||
"email": "[email protected]" | ||
}, | ||
headers=auth_headers, | ||
) | ||
assert response.status_code == 401, response.text | ||
|
||
def test_send_invite_email_requires_at_least_one_admin_email(self, with_db, with_client): | ||
"""Ensures send_invite_email requires an admin user""" | ||
|
||
os.environ['APP_ADMIN_ALLOW_LIST'] = '' | ||
|
||
response = with_client.post( | ||
"/invite/send", | ||
json={ | ||
"email": "[email protected]" | ||
}, | ||
headers=auth_headers, | ||
) | ||
assert response.status_code == 401, response.text | ||
|
||
def test_send_invite_email(self, with_db, with_client): | ||
"""Ensures send_invite_email requires an admin user""" | ||
|
||
os.environ['APP_ADMIN_ALLOW_LIST'] = '@example.org' | ||
|
||
invite_email = '[email protected]' | ||
|
||
with with_db() as db: | ||
subscriber = repo.subscriber.get_by_email(db, invite_email) | ||
assert subscriber is None | ||
|
||
response = with_client.post( | ||
"/invite/send", | ||
json={ | ||
'email': invite_email | ||
}, | ||
headers=auth_headers, | ||
) | ||
assert response.status_code == 200, response.text | ||
|
||
with with_db() as db: | ||
subscriber = repo.subscriber.get_by_email(db, invite_email) | ||
assert subscriber is not None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
<template> | ||
<div class="flex flex-col items-center justify-center gap-4"> | ||
<div class="flex w-full flex-row items-center justify-between"> | ||
<div> | ||
<span class="font-bold">{{ paginatedDataList.length }}</span> {{ dataName }} | ||
</div> | ||
<list-pagination | ||
:list-length="dataList.length" | ||
:page-size="pageSize" | ||
@update="updatePage" | ||
/> | ||
</div> | ||
<div class="data-table"> | ||
<table> | ||
<thead> | ||
<tr> | ||
<th v-if="allowMultiSelect"> | ||
<!-- Decide if we want to select all for the paginated list or all data --> | ||
</th> | ||
<th v-for="column in columns" :key="column.key">{{ column.name }}</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
<tr v-for="datum in paginatedDataList" :key="datum"> | ||
<td v-if="allowMultiSelect"> | ||
<input type="checkbox" @change="(evt) => onFieldSelect(evt, datum)" /> | ||
</td> | ||
<td v-for="(fieldData, fieldKey) in datum" :key="fieldKey"> | ||
<span v-if="fieldData.type === tableDataType.text"> | ||
{{ fieldData.value }} | ||
</span> | ||
<span v-else-if="fieldData.type === tableDataType.link"> | ||
<a :href="fieldData.link" target="_blank">{{ fieldData.value }}</a> | ||
</span> | ||
<span v-else-if="fieldData.type === tableDataType.button"> | ||
<primary-button v-if="fieldData.buttonType === tableDataButtonType.primary" @click="emit('fieldClick', datum)">{{ fieldData.value }}</primary-button> | ||
<secondary-button v-else-if="fieldData.buttonType === tableDataButtonType.secondary" @click="emit('fieldClick', datum)">{{ fieldData.value }}</secondary-button> | ||
<caution-button v-else-if="fieldData.buttonType === tableDataButtonType.caution" @click="emit('fieldClick', datum)">{{ fieldData.value }}</caution-button> | ||
</span> | ||
</td> | ||
</tr> | ||
<tr v-if="paginatedDataList.length === 0"> | ||
<td :colspan="columnSpan">{{ t('error.dataSourceIsEmpty', {name: dataName}) }}</td> | ||
</tr> | ||
</tbody> | ||
<tfoot> | ||
<tr> | ||
<th :colspan="columnSpan"> | ||
<slot name="footer"></slot> | ||
</th> | ||
</tr> | ||
</tfoot> | ||
</table> | ||
</div> | ||
</div> | ||
</template> | ||
|
||
<script setup> | ||
/** | ||
* Data Table | ||
* @typedef {{type: tableDataType, value: string, link?: string, buttonType?: tableDataButtonType }} DataField | ||
* @typedef {{name: string, key: string}} DataColumn | ||
* | ||
* @param allowMultiSelect {boolean} - Displays checkboxes next to each row, and emits the `fieldSelect` event with a list of currently selected rows | ||
* @param dataName {string} - The name for the object being represented on the table | ||
* @param columns {Array<DataColumn>} - List of columns to be displayed (these don't filter data, filter that yourself!) | ||
* @param dataList {Array<DataField>} - List of data to be displayed | ||
*/ | ||
import ListPagination from '@/elements/ListPagination.vue'; | ||
import { useI18n } from 'vue-i18n'; | ||
import { | ||
computed, onMounted, ref, toRefs, | ||
} from 'vue'; | ||
import { tableDataButtonType, tableDataType } from '@/definitions'; | ||
import PrimaryButton from '@/elements/PrimaryButton.vue'; | ||
import SecondaryButton from '@/elements/SecondaryButton.vue'; | ||
import CautionButton from '@/elements/CautionButton.vue'; | ||
const props = defineProps({ | ||
allowMultiSelect: Boolean, | ||
dataName: String, | ||
dataList: Array, | ||
columns: Array, | ||
}); | ||
const { | ||
dataList, columns, dataName, allowMultiSelect, | ||
} = toRefs(props); | ||
const { t } = useI18n(); | ||
const emit = defineEmits(['fieldSelect', 'fieldClick']); | ||
// pagination | ||
const pageSize = 10; | ||
const currentPage = ref(0); | ||
const updatePage = (index) => { | ||
currentPage.value = index; | ||
}; | ||
const columnSpan = computed(() => (columns.value.length + (allowMultiSelect.value ? 1 : 0))); | ||
const selectedFields = ref([]); | ||
const paginatedDataList = computed(() => (dataList.value && dataList.value.length | ||
? dataList.value.slice(currentPage.value * pageSize, (currentPage.value + 1) * pageSize) | ||
: [])); | ||
const onFieldSelect = (evt, fieldData) => { | ||
console.log(evt, fieldData); | ||
const isChecked = evt?.target?.checked; | ||
if (isChecked) { | ||
selectedFields.value.push(fieldData); | ||
} else { | ||
const index = selectedFields.value.indexOf(fieldData); | ||
if (index !== -1) { | ||
selectedFields.value.splice(index, 1); | ||
} | ||
} | ||
console.log('->', selectedFields.value); | ||
emit('fieldSelect', selectedFields.value); | ||
}; | ||
onMounted(() => { | ||
console.log(dataList.value); | ||
}); | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.