<field reporter:label="ID" name="id" reporter:datatype="id" />
<field reporter:label="Course" name="course" reporter:datatype="link" />
<field reporter:label="User" name="usr" reporter:datatype="link" />
- <field reporter:label="User Role" name="usr_role" reporter:datatype="text" />
- <field reporter:label="OPAC Viewable?" name="is_public" reporter:datatype="bool" />
+ <field reporter:label="User Role" name="usr_role" reporter:datatype="link" />
</fields>
<links>
<link field="course" reltype="has_a" key="id" map="" class="acmc" />
<link field="usr" reltype="has_a" key="id" map="" class="au" />
+ <link field="usr_role" reltype="has_a" key="id" map="" class="acmr" />
</links>
<permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
<actions>
</actions>
</permacrud>
</class>
+ <class id="acmr" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="asset::course_module_role" oils_persist:tablename="asset.course_module_role" reporter:label="Course Role" oils_persist:field_safe="true">
+ <fields oils_persist:primary="id" oils_persist:sequence="asset.course_module_role_id_seq">
+ <field reporter:label="Role ID" name="id" reporter:datatype="id" reporter:selector="name"/>
+ <field reporter:label="Name" name="name" reporter:datatype="text" oils_persist:i18n="true" oils_obj:required="true"/>
+ <field reporter:label="OPAC Viewable?" name="is_public" reporter:datatype="bool" />
+ </fields>
+ <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+ <actions>
+ <create permission="MANAGE_RESERVES" global_required="true" />
+ <retrieve/>
+ <update permission="MANAGE_RESERVES" global_required="true" />
+ <delete permission="MANAGE_RESERVES" global_required="true" />
+ </actions>
+ </permacrud>
+ </class>
<class id="acnc" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="asset::call_number_class" oils_persist:tablename="asset.call_number_class" reporter:label="Call number classification scheme">
<fields oils_persist:primary="id" oils_persist:sequence="asset.call_number_class_id_seq">
<div class="input-group-prepend">
<label for="associate-user-role" class="input-group-text" i18n>Role</label>
</div>
- <input type="text" [(ngModel)]="userRoleInput" id="associate-user-role"
- [disabled]="currentCourse && currentCourse.is_archived() == 't'"
- placeholder-i18n placeholder="e.g. Student, TA, Instructor..."
- class="flex-grow-1" />
+ <eg-combobox idlClass="acmr" [(ngModel)]="userRoleInput"
+ [disabled]="currentCourse && currentCourse.is_archived() == 't'">
+ </eg-combobox>
</div>
</div>
</div>
<div class="row mt-3">
- <div [ngClass]="isDialog() ? 'offset-md-6 col-md-4' : 'col-md-6'">
- <div class="input-group">
- <div class="input-group-prepend">
- <div class="input-group-text">
- <label for="associate-user-public" i18n>Is Public Role?</label>
- </div>
- </div>
- <div class="input-group-append">
- <div class="input-group-text">
- <input type="checkbox" [(ngModel)]="isPublicRole" id="associate-user-public"
- [disabled]="currentCourse && currentCourse.is_archived() == 't'"
- aria-label="Checkbox for allowing user to display on the OPAC Course Page" />
- </div>
- </div>
- </div>
- </div>
<div class="text-right" [ngClass]="isDialog() ? 'col-md-2' : 'col-md-6'">
<button class="btn btn-primary"
[disabled]="currentCourse && currentCourse.is_archived() == 't'"
<eg-grid-column label="Preferred Second Name" path="usr.pref_second_given_name"[hidden]="true" i18n-label></eg-grid-column>
<eg-grid-column label="Preferred Family Name" path="usr.pref_family_name"[hidden]="true" i18n-label></eg-grid-column>
<eg-grid-column label="Preferred Suffix" path="usr.pref_suffix" [hidden]="true" i18n-label></eg-grid-column>
- <eg-grid-column label="User Role" path="usr_role" i18n-label></eg-grid-column>
- <eg-grid-column label="Viewable on OPAC" path="is_public" i18n-label datatype="bool"></eg-grid-column>
+ <eg-grid-column label="User Role" path="usr_role.name" i18n-label></eg-grid-column>
+ <eg-grid-column label="Viewable on OPAC" path="usr_role.is_public" i18n-label datatype="bool"></eg-grid-column>
</eg-grid>
</div>
</div>
import {NgbModal} from '@ng-bootstrap/ng-bootstrap';
import {GridDataSource} from '@eg/share/grid/grid';
import {GridComponent} from '@eg/share/grid/grid.component';
-import {IdlObject, IdlService} from '@eg/core/idl.service';
+import {IdlObject} from '@eg/core/idl.service';
import {StringComponent} from '@eg/share/string/string.component';
import {FmRecordEditorComponent} from '@eg/share/fm-editor/fm-editor.component';
import {ToastService} from '@eg/share/toast/toast.service';
import {CourseService} from '@eg/staff/share/course.service';
+import {ComboboxEntry} from '@eg/share/combobox/combobox.component';
@Component({
selector: 'eg-course-associate-users-dialog',
userEditFailedString: StringComponent;
usersDataSource: GridDataSource;
userBarcode: String;
- userRoleInput: String;
- isPublicRole: Boolean;
+ userRoleInput: ComboboxEntry;
constructor(
private auth: AuthService,
const args = {
currentCourse: this.currentCourse,
barcode: barcode.trim(),
- role: this.userRoleInput,
- is_public: this.isPublicRole
};
+ if (this.userRoleInput) {
+ args['role'] = this.userRoleInput.id;
+ }
+
this.userBarcode = null;
this.net.request(
<eg-grid-column label="Section Number" name="section_number" i18n-label></eg-grid-column>
<eg-grid-column label="Is Archived?" name="is_archived" i18n-label datatype="bool"></eg-grid-column>
</eg-grid>
- </div>
+ </div>
</ng-template>
</li>
<li ngbNavItem>
<eg-admin-page idlClass="acmt"></eg-admin-page>
</ng-template>
</li>
+ <li ngbNavItem>
+ <a ngbNavLink i18n>Course roles</a>
+ <ng-template ngbNavContent>
+ <eg-admin-page idlClass="acmr"></eg-admin-page>
+ </ng-template>
+ </li>
</ul>
<div [ngbNavOutlet]="courseListNav"></div>
getUsers(course_ids?: Number[]): Observable<IdlObject> {
const flesher = {
flesh: 1,
- flesh_fields: {'acmcu': ['usr']}
+ flesh_fields: {'acmcu': ['usr', 'usr_role']}
};
if (!course_ids) {
return this.pcrud.retrieveAll('acmcu',
associateUsers(patron_id, args) {
const new_user = this.idl.create('acmcu');
- if (args.is_public) { new_user.is_public(args.is_public); }
if (args.role) { new_user.usr_role(args.role); }
new_user.course(args.currentCourse.id());
new_user.usr(patron_id);
my %patrons;
$filter->{course} = $course_id;
- $filter->{is_public} = 't'
+ $filter->{usr_role}->{is_public} = 't'
unless ($self->api_name =~ /\.staff/) and $e->allowed('MANAGE_RESERVES');
- $users->{list} = $e->search_asset_course_module_course_users($filter, {order_by => {acmcu => 'id'}});
+ $users->{list} = $e->search_asset_course_module_course_users($filter, {flesh => 1, flesh_fields => {acmcu => ['usr_role']}, order_by => {acmcu => 'id'}});
for my $course_user (@{$users->{list}}) {
my $patron = {};
$patron->{id} = $course_user->id;
"select" => {"acmcu" => [
'id',
'usr',
- 'is_public'
]},
# TODO: We need to support the chosen library as well...
- "where" => {'+acmcu' => 'is_public'}
+ "where" => {'usr_role' => {'in' => {'select' => {'acmr' => ['id']}, 'where' => {'+acmr' => 'is_public'}}}}
});
$results = $e->json_query({
"from" => "au",
"acmcu" => ['usr']
},
"where" => {'-and' => [
- {'+acmcu' => 'is_public'},
+ {'usr_role' => { 'in' => {
+ 'from' => 'acmr',
+ "select" => {
+ "acmr" => ['id']
+ },
+ "where" => {'+acmr' => 'is_public'}}}},
{"course" => { "in" =>{
"from" => "acmc",
"select" => {
is_archived BOOLEAN DEFAULT false
);
+CREATE TABLE asset.course_module_role (
+ id SERIAL PRIMARY KEY,
+ name TEXT UNIQUE NOT NULL,
+ is_public BOOLEAN NOT NULL DEFAULT false
+);
+
CREATE TABLE asset.course_module_course_users (
id SERIAL PRIMARY KEY,
course INT NOT NULL REFERENCES asset.course_module_course (id),
usr INT NOT NULL REFERENCES actor.usr (id),
- usr_role TEXT,
- is_public BOOLEAN NOT NULL DEFAULT false
+ usr_role INT REFERENCES asset.course_module_role (id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED
);
CREATE TABLE asset.course_module_course_materials (
FROM config.bib_source
WHERE source='Course materials module';
+INSERT INTO asset.course_module_role (id, name, is_public) VALUES
+(1, oils_i18n_gettext(1, 'Instructor', 'acmr', 'name'), true),
+(2, oils_i18n_gettext(2, 'Teaching assistant', 'acmr', 'name'), true),
+(3, oils_i18n_gettext(2, 'Student', 'acmr', 'name'), false);
+
INSERT INTO config.workstation_setting_type (name, grp, datatype, label)
VALUES (
is_archived BOOLEAN NOT NULL DEFAULT false;
);
+CREATE TABLE asset.course_module_role (
+ id SERIAL PRIMARY KEY,
+ name TEXT UNIQUE NOT NULL,
+ is_public BOOLEAN NOT NULL DEFAULT false
+);
+
CREATE TABLE asset.course_module_course_users (
id SERIAL PRIMARY KEY,
course INT NOT NULL REFERENCES asset.course_module_course (id),
usr INT NOT NULL REFERENCES actor.usr (id),
- usr_role TEXT,
- is_public BOOLEAN NOT NULL DEFAULT false
+ usr_role INT REFERENCES asset.course_module_role (id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED
);
CREATE TABLE asset.course_module_course_materials (
item INT REFERENCES asset.copy (id),
relationship TEXT,
record INT REFERENCES biblio.record_entry (id),
- temporary_record BOOLEAN,
- original_location INT REFERENCES asset.copy_location,
- original_status INT REFERENCES config.copy_status,
- original_circ_modifier TEXT, --REFERENCES config.circ_modifier,
- original_callnumber INT REFERENCES asset.call_number,
+ temporary_record BOOLEAN,
+ original_location INT REFERENCES asset.copy_location,
+ original_status INT REFERENCES config.copy_status,
+ original_circ_modifier TEXT, --REFERENCES config.circ_modifier
+ original_callnumber INT REFERENCES asset.call_number,
unique (course, item, record)
);
id SERIAL PRIMARY KEY,
name TEXT UNIQUE NOT NULL,
owning_lib INT REFERENCES actor.org_unit (id),
- start_date TIMESTAMP WITH TIME ZONE,
- end_date TIMESTAMP WITH TIME ZONE
+ start_date TIMESTAMP WITH TIME ZONE,
+ end_date TIMESTAMP WITH TIME ZONE
);
+INSERT INTO asset.course_module_role (id, name, is_public) VALUES
+(1, oils_i18n_gettext(1, 'Instructor', 'acmr', 'name'), true),
+(2, oils_i18n_gettext(2, 'Teaching assistant', 'acmr', 'name'), true),
+(3, oils_i18n_gettext(2, 'Student', 'acmr', 'name'), false);
+
CREATE TABLE asset.course_module_term_course_map (
id BIGSERIAL PRIMARY KEY,
term INT NOT NULL REFERENCES asset.course_module_term (id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
href="[%
mkurl(ctx.opac_root _ '/results', {qtype => 'instructor', query => instructorString})
%]" rel="nofollow" vocab="">
- [% instructorString %] ([% l(instructor.usr_role) %])</a>.
+ [% instructorString %] ([% l(instructor.usr_role.name) %])</a>.
[% END %]
</div>
<div>
ELSE;
instructorString = instructorString _ instructor.first_given_name;
END;
- instructorString = instructorString _ ' (' _ l(instructor.usr_role) _ ')'; %]
+ instructorString = instructorString _ ' (' _ l(instructor.usr_role.name) _ ')'; %]
<span class="course-instructor-div">[% instructorString %].</span>
[% END %]
</div>