timApp.answer package#

Submodules#

timApp.answer.answer module#

class timApp.answer.answer.Answer(**kwargs)[source]#

Bases: sqlalchemy.ext.declarative.api.Model

An answer to a task.

annotations#
answered_on#

Answer timestamp.

content#

Answer content.

property content_as_json: dict#
get_answer_number() int[source]#
property has_many_collaborators: bool#
id#

Answer identifier.

last_points_modifier#

The UserGroup who modified the points last. Null if the points have been given by the task automatically.

origin_doc_id#

The document in which the answer was saved

property parsed_task_id: timApp.plugin.taskid.TaskId#
plugin_type: timApp.plugin.plugintype.PluginType | None#
plugin_type_id#

Plugin type the answer was saved on

points#

Points.

saver#
task_id#

Task id to which this answer was posted. In the form “doc_id.name”, for example “2.task1”.

property task_name: str#
to_json() dict[source]#
uploads#
users#
users_all#
valid#

Whether this answer is valid.

class timApp.answer.answer.AnswerSaver(**kwargs)[source]#

Bases: sqlalchemy.ext.declarative.api.Model

Holds information about who has saved an answer. For example, in teacher view, “Save teacher’s fix” would store the teacher in this table.

answer_id#
user_id#

timApp.answer.answer_models module#

class timApp.answer.answer_models.AnswerTag(**kwargs)[source]#

Bases: sqlalchemy.ext.declarative.api.Model

Tags for an Answer.

TODO: Answer should be a Block and the tags would then come from the tag table.

answer_id#
id#
tag#
class timApp.answer.answer_models.AnswerUpload(block, answer=None)[source]#

Bases: sqlalchemy.ext.declarative.api.Model

Associates uploaded files (Block with type BlockType.AnswerUpload) with Answers.

answer#
answer_id#
block#
upload_block_id#
class timApp.answer.answer_models.UserAnswer(**kwargs)[source]#

Bases: sqlalchemy.ext.declarative.api.Model

Associates Users with Answers.

answer_id#
id#
user_id#

timApp.answer.answers module#

class timApp.answer.answers.AgeOptions(value)[source]#

Bases: enum.Enum

An enumeration.

ALL = 'all'#
MAX = 'max'#
MIN = 'min'#
class timApp.answer.answers.AllAnswersOptions(period: timApp.util.answerutil.PeriodOptions = <PeriodOptions.WHENEVER: 'whenever'>, period_from: datetime.datetime | None = None, period_to: datetime.datetime | None = None, group: str | None = None, age: timApp.answer.answers.AgeOptions = <AgeOptions.MAX: 'max'>, valid: timApp.answer.answers.ValidityOptions = <ValidityOptions.VALID: '1'>, name: timApp.answer.answers.NameOptions = <NameOptions.BOTH: 'both'>, sort: timApp.answer.answers.SortOptions = <SortOptions.TASK: 'task'>, format: timApp.answer.answers.FormatOptions = <FormatOptions.TEXT: 'text'>, consent: timApp.user.user.Consent | None = None, print: timApp.answer.answers.AnswerPrintOptions = <AnswerPrintOptions.ALL: 'all'>, salt: str | None = None, salt_len: int = 32)[source]#

Bases: timApp.util.answerutil.AnswerPeriodOptions

age: timApp.answer.answers.AgeOptions = 'max'#
consent: timApp.user.user.Consent | None = None#
format: timApp.answer.answers.FormatOptions = 'text'#
group: str | None = None#
name: timApp.answer.answers.NameOptions = 'both'#
print: timApp.answer.answers.AnswerPrintOptions = 'all'#
salt: str | None = None#
salt_len: int = 32#
sort: timApp.answer.answers.SortOptions = 'task'#
valid: timApp.answer.answers.ValidityOptions = '1'#
class timApp.answer.answers.AnswerPrintOptions(value)[source]#

Bases: enum.Enum

An enumeration.

ALL = 'all'#
ANSWERS = 'answers'#
ANSWERS_NO_LINE = 'answersnoline'#
HEADER = 'header'#
KORPPI = 'korppi'#
class timApp.answer.answers.ExistingAnswersInfo(latest_answer: timApp.answer.answer.Answer | None, count: int)[source]#

Bases: object

count: int#
latest_answer: timApp.answer.answer.Answer | None#
class timApp.answer.answers.FormatOptions(value)[source]#

Bases: enum.Enum

An enumeration.

JSON = 'json'#
TEXT = 'text'#
class timApp.answer.answers.NameOptions(value)[source]#

Bases: enum.Enum

An enumeration.

ANON = 'anonymous'#
BOTH = 'both'#
PSEUDO = 'pseudonym'#
USERNAME = 'username'#
class timApp.answer.answers.ResultGroup[source]#

Bases: dict

linktext: str#
task_sum: float | None#
text: str#
total_sum: float | None#
velp_sum: float | None#
class timApp.answer.answers.SortOptions(value)[source]#

Bases: enum.Enum

An enumeration.

TASK = 'task'#
USERNAME = 'username'#
class timApp.answer.answers.SumFields[source]#

Bases: TypedDict

task_sum: float | None#
total_sum: float | None#
velp_sum: float | None#
exception timApp.answer.answers.TooLargeAnswerException[source]#

Bases: Exception

class timApp.answer.answers.UserPointGroup[source]#

Bases: dict

task_sum: float | None#
tasks: list[timApp.answer.answers.UserTaskEntry]#
total_sum: float | None#
velp_sum: float | None#
velped_task_count: int#
class timApp.answer.answers.UserPointInfo[source]#

Bases: dict

groups: DefaultDict[str, timApp.answer.answers.UserPointGroup]#
task_sum: float | None#
total_sum: float | None#
velp_sum: float | None#
class timApp.answer.answers.UserPoints[source]#

Bases: TypedDict

groups: dict[str, timApp.answer.answers.ResultGroup]#
task_count: int#
task_points: float | None#
total_points: float | None#
user: timApp.user.user.User#
velp_points: float | None#
velped_task_count: int#
class timApp.answer.answers.UserTaskEntry[source]#

Bases: TypedDict

task_count: int#
task_id: str#
task_points: float | None#
total_points: float | None#
user: timApp.user.user.User#
velp_points: float | None#
velped_task_count: int#
class timApp.answer.answers.ValidityOptions(value)[source]#

Bases: enum.Enum

An enumeration.

ALL = 'all'#
INVALID = '0'#
VALID = '1'#
timApp.answer.answers.add_missing_users_from_group(result: list, usergroup: timApp.user.usergroup.UserGroup) list[source]#
timApp.answer.answers.flatten_points_result(rule: timApp.answer.pointsumrule.PointSumRule, rule_groups: dict[str, timApp.answer.pointsumrule.Group], result: DefaultDict[int, timApp.answer.answers.UserPointInfo], task_counts: dict[int, int], user_map: dict[int, timApp.user.user.User]) list[timApp.answer.answers.UserPoints][source]#
timApp.answer.answers.get_all_answer_initial_query(period_from: datetime.datetime, period_to: datetime.datetime, task_ids: list[timApp.plugin.taskid.TaskId], valid: timApp.answer.answers.ValidityOptions) sqlalchemy.orm.query.Query[source]#
timApp.answer.answers.get_all_answers(task_ids: list[timApp.plugin.taskid.TaskId], options: timApp.answer.answers.AllAnswersOptions) list[str] | list[dict][source]#

Gets all answers to the specified tasks.

Parameters
  • task_ids – The ids of the tasks to get answers for.

  • options – The options for getting and printing the answers.

timApp.answer.answers.get_existing_answers_info(users: list[timApp.user.user.User], task_id: timApp.plugin.taskid.TaskId) timApp.answer.answers.ExistingAnswersInfo[source]#
timApp.answer.answers.get_latest_answers_query(task_id: timApp.plugin.taskid.TaskId, users: list[timApp.user.user.User]) sqlalchemy.orm.query.Query[source]#
timApp.answer.answers.get_latest_valid_answers_query(task_id: timApp.plugin.taskid.TaskId, users: list[timApp.user.user.User]) sqlalchemy.orm.query.Query[source]#
timApp.answer.answers.get_points_by_rule(rule: timApp.answer.pointsumrule.PointSumRule | None, task_ids: list[timApp.plugin.taskid.TaskId], user_ids: Optional[list[int]] = None, answer_filter: Optional[Any] = None, force_user: Optional[timApp.user.user.User] = None) list[timApp.answer.answers.UserPoints] | list[timApp.answer.answers.UserTaskEntry][source]#

Computes the point sum from given tasks according to the given point rule.

Parameters
  • force_user – Whether to force at least one result user if the result would be empty otherwise.

  • answer_filter – Optional additional filter for answers.

  • rule – The points rule.

  • task_ids – The list of task ids to consider.

  • user_ids – The list of users for which to compute the sum.

Returns

The computed result.

timApp.answer.answers.get_users_for_tasks(task_ids: list[timApp.plugin.taskid.TaskId], user_ids: Optional[list[int]] = None, group_by_user: bool = True, group_by_doc: bool = False, answer_filter: Optional[Any] = None) list[timApp.answer.answers.UserTaskEntry][source]#
timApp.answer.answers.is_redundant_answer(content: str, existing_answers: timApp.answer.answers.ExistingAnswersInfo, ptype: timApp.plugin.plugintype.PluginTypeBase | None, valid: bool) bool[source]#
timApp.answer.answers.round_if_not_none(num: Optional[timApp.answer.answers.T], digits: int = 2) Optional[timApp.answer.answers.T][source]#
timApp.answer.answers.save_answer(users: list[timApp.user.user.User], task_id: timApp.plugin.taskid.TaskId, content: Any, points: float | None, tags: Optional[list[str]] = None, valid: bool = True, points_given_by: Optional[int] = None, force_save: bool = False, saver: Optional[timApp.user.user.User] = None, plugintype: Optional[timApp.plugin.plugintype.PluginTypeLazy] = None, max_content_len: Optional[int] = None, origin: Optional[timApp.document.viewcontext.OriginInfo] = None) timApp.answer.answer.Answer | None[source]#

Saves an answer to the database.

Parameters
  • max_content_len – Maximum length for answer content.

  • plugintype – The plugin type.

  • saver – Who saved the answer.

  • points_given_by – The usergroup id who gave the points, or None if they were given by a plugin.

  • tags – Tags for the answer.

  • valid – Whether the answer is considered valid (e.g. sent before deadline, etc.)

  • users – The users to which the answer belongs.

  • task_id – The id of the task.

  • content – The content of the answer.

  • points – Points for the task.

  • force_save – Whether to force to save the answer even if the latest existing answer has the same content.

  • origin – If known, the document from which the answer was sent.

timApp.answer.answers.sum_and_round(generator: Generator[timApp.answer.answers.T, None, None], digits: int = 2) Optional[timApp.answer.answers.T][source]#
timApp.answer.answers.valid_answers_query(task_ids: list[timApp.plugin.taskid.TaskId]) sqlalchemy.orm.query.Query[source]#
timApp.answer.answers.valid_taskid_filter(task_ids: list[timApp.plugin.taskid.TaskId]) sqlalchemy.orm.query.Query[source]#

timApp.answer.backup module#

timApp.answer.backup.get_backup_answer_file() pathlib.Path[source]#
timApp.answer.backup.save_answer_backup(answer: timApp.answer.exportedanswer.ExportedAnswer, secret: str) flask.wrappers.Response[source]#
timApp.answer.backup.send_answer_backup_if_enabled(a: timApp.answer.answer.Answer) None[source]#
timApp.answer.backup.sync_user_group_memberships_if_enabled(user: timApp.user.user.User) None[source]#

timApp.answer.exportedanswer module#

class timApp.answer.exportedanswer.ExportedAnswer(content: str, email: str, points: int | float | None, task: str, time: datetime.datetime, valid: bool, doc: str, host: str | None = None)[source]#

Bases: object

content: str#
doc: str#
email: str#
host: str | None = None#
points: int | float | None#
task: str#
time: datetime.datetime#
valid: bool#

timApp.answer.feedbackanswer module#

timApp.answer.feedbackanswer.compile_csv(qq: typing.Iterable[tuple[timApp.answer.answer.Answer, timApp.user.user.User]], printname: bool, hide_names: bool, exp_answers: str, s_user: [<class 'str'>], dec: str)[source]#

Compile data into more csv friendly form.

Parameters
  • qq – List of Tuples containing Answers and Users.

  • printname – Parameter whether to show full name.

  • hide_names – Parameter whether to show users anonymously.

  • exp_answers – Parameter for filtering users.

  • s_user – Visible users with first one always being the selected user.

  • dec – Format for the decimal separator.

Returns

Returns test results as list.

timApp.answer.feedbackanswer.get_all_feedback_answers(task_ids: list[timApp.plugin.taskid.TaskId], hide_names: bool, printname: bool, valid: str, exp_answers: str, users: list[str], period_from: datetime.datetime, period_to: datetime.datetime, dec: str)[source]#

Get feedback answer results.

Parameters
  • task_ids – List of task ids.

  • hide_names – Parameter for whether to show users anonymously.

  • printname – Parameter for whether to show full name.

  • valid – Parameter for validity filter; “0”, “1”, “all”.

  • exp_answers – Parameter for filtering users.

  • users – List of visible users with selected user always first.

  • period_from – The minimum answering time for answers.

  • period_to – The maximum answering time for answers.

  • dec – Format for the decimal separator.

Returns

Compiled list of test results.

timApp.answer.feedbackanswer.print_feedback_report(doc_path: str)[source]#

Route to Feedback report.

Parameters

doc_path – URL for the document.

Returns

report in a CSV-form.

timApp.answer.pointsumrule module#

class timApp.answer.pointsumrule.CountModel(best: int | None = None, worst: int | None = None)[source]#

Bases: object

best: int | None = None#
worst: int | None = None#
class timApp.answer.pointsumrule.Group(name: str, data: str | dict)[source]#

Bases: object

check_match(task_id: str) bool[source]#
class timApp.answer.pointsumrule.PointCountMethod(value)[source]#

Bases: enum.Enum

Point count method for scoreboard.

latest = 1#
max = 2#
class timApp.answer.pointsumrule.PointSumRule(data: dict)[source]#

Bases: object

find_groups(task_id: str) Generator[str, None, None][source]#
get_groups(task_ids: Optional[list[timApp.plugin.taskid.TaskId]] = None) dict[str, timApp.answer.pointsumrule.Group][source]#
class timApp.answer.pointsumrule.PointSumRuleModel(count: timApp.answer.pointsumrule.CountModel = CountModel(best=9999, worst=None), scoreboard: timApp.answer.pointsumrule.ScoreboardOptions = ScoreboardOptions(groups=[]), include_groupless: bool = False, point_count_method: timApp.answer.pointsumrule.PointCountMethod = <PointCountMethod.latest: 1>)[source]#

Bases: object

count: timApp.answer.pointsumrule.CountModel = CountModel(best=9999, worst=None)#
include_groupless: bool = False#
point_count_method: timApp.answer.pointsumrule.PointCountMethod = 1#
scoreboard: timApp.answer.pointsumrule.ScoreboardOptions = ScoreboardOptions(groups=[])#
class timApp.answer.pointsumrule.PointType(value)[source]#

Bases: enum.Enum

An enumeration.

task = 1#
velp = 2#
class timApp.answer.pointsumrule.ScoreboardOptions(groups: list[str] = <factory>)[source]#

Bases: object

groups: list[str]#

timApp.answer.routes module#

Answer-related routes.

class timApp.answer.routes.AnswerRouteResult(result: dict[str, Any], plugin: timApp.plugin.plugin.Plugin)[source]#

Bases: object

plugin: timApp.plugin.plugin.Plugin#
result: dict[str, Any]#
class timApp.answer.routes.FieldInfo(data: dict[str, Union[str, float, NoneType]], aliases: dict[str, str], fieldnames: list[str], graphdata: timApp.answer.routes.GraphData)[source]#

Bases: object

aliases: dict[str, str]#
data: dict[str, Union[str, float, NoneType]]#
fieldnames: list[str]#
graphdata: timApp.answer.routes.GraphData#
class timApp.answer.routes.FieldSaveRequest[source]#

Bases: TypedDict

allowMissing: bool | None#
createMissingUsers: bool | None#
groups: timApp.answer.routes.JsrunnerGroups | None#
ignoreMissing: bool | None#
missingUsers: Optional[Any]#
savedata: list[timApp.answer.routes.FieldSaveUserEntry] | None#
class timApp.answer.routes.FieldSaveResult(users_created: list[timApp.user.user.User] = <factory>, users_missing: list[timApp.user.user.UserInfo] = <factory>, fields_changed: int = 0, fields_unchanged: int = 0, fields_ignored: int = 0)[source]#

Bases: object

fields_changed: int = 0#
fields_ignored: int = 0#
fields_unchanged: int = 0#
users_created: list[timApp.user.user.User]#
users_missing: list[timApp.user.user.UserInfo]#
class timApp.answer.routes.FieldSaveUserEntry[source]#

Bases: TypedDict

fields: dict[str, str]#
user: int#
class timApp.answer.routes.GraphData[source]#

Bases: TypedDict

data: list[str | float | None]#
labels: list[str]#
class timApp.answer.routes.JsRunnerAnswerModel(input: timApp.answer.routes.JsRunnerInputModel, ref_from: timApp.answer.routes.RefFrom | None = None, abData: dict[str, typing.Any] | marshmallow.utils._Missing = <marshmallow.missing>)[source]#

Bases: object

abData: dict[str, Any] | marshmallow.utils._Missing = <marshmallow.missing>#
input: timApp.answer.routes.JsRunnerInputModel#
ref_from: timApp.answer.routes.RefFrom | None = None#
class timApp.answer.routes.JsRunnerInputModel(nosave: bool | marshmallow.utils._Missing = <marshmallow.missing>, userNames: list[str] | marshmallow.utils._Missing = <marshmallow.missing>, paramComps: dict[str, str] | marshmallow.utils._Missing = <marshmallow.missing>, includeUsers: timApp.util.get_fields.MembershipFilter | marshmallow.utils._Missing = <marshmallow.missing>)[source]#

Bases: object

includeUsers: timApp.util.get_fields.MembershipFilter | marshmallow.utils._Missing = <marshmallow.missing>#
nosave: bool | marshmallow.utils._Missing = <marshmallow.missing>#
paramComps: dict[str, str] | marshmallow.utils._Missing = <marshmallow.missing>#
userNames: list[str] | marshmallow.utils._Missing = <marshmallow.missing>#
class timApp.answer.routes.JsRunnerMarkupModel(accessDuration: int | None | marshmallow.utils._Missing = <marshmallow.missing>, accessEndText: str | None | marshmallow.utils._Missing = <marshmallow.missing>, anonymous: bool | None | marshmallow.utils._Missing = <marshmallow.missing>, answerLimit: int | None | marshmallow.utils._Missing = <marshmallow.missing>, automd: bool | None | marshmallow.utils._Missing = <marshmallow.missing>, buttonNewTask: str | None | marshmallow.utils._Missing = <marshmallow.missing>, cache: bool | None | marshmallow.utils._Missing = <marshmallow.missing>, deadline: Union[tim_common.markupmodels.PluginDateTime, datetime.datetime, NoneType, marshmallow.utils._Missing] = <marshmallow.missing>, fields: list[str] | marshmallow.utils._Missing = <marshmallow.missing>, floatHeader: str | None | marshmallow.utils._Missing = <marshmallow.missing>, floatSize: tuple[int, int] | None | marshmallow.utils._Missing = <marshmallow.missing>, header: str | None | marshmallow.utils._Missing = <marshmallow.missing>, headerText: str | None | marshmallow.utils._Missing = <marshmallow.missing>, hideBrowser: bool | marshmallow.utils._Missing | None = <marshmallow.missing>, initNewAnswer: str | None | marshmallow.utils._Missing = <marshmallow.missing>, lazy: bool | marshmallow.utils._Missing = <marshmallow.missing>, maxHeight: str | None | marshmallow.utils._Missing = <marshmallow.missing>, minHeight: str | None | marshmallow.utils._Missing = <marshmallow.missing>, pointsRule: tim_common.markupmodels.PointsRule | None | marshmallow.utils._Missing = <marshmallow.missing>, pointsText: str | None | marshmallow.utils._Missing = <marshmallow.missing>, postprogram: str | marshmallow.utils._Missing = <marshmallow.missing>, postoutput: str | marshmallow.utils._Missing = <marshmallow.missing>, showPoints: bool | None | marshmallow.utils._Missing = <marshmallow.missing>, starttime: Union[tim_common.markupmodels.PluginDateTime, datetime.datetime, NoneType, marshmallow.utils._Missing] = <marshmallow.missing>, showInView: bool = False, stem: str | None | marshmallow.utils._Missing = <marshmallow.missing>, triesText: str | None | marshmallow.utils._Missing = <marshmallow.missing>, useCurrentUser: bool | None | marshmallow.utils._Missing = <marshmallow.missing>, texafterprint: str | None | marshmallow.utils._Missing = <marshmallow.missing>, texbeforeprint: str | None | marshmallow.utils._Missing = <marshmallow.missing>, texprint: str | None | marshmallow.utils._Missing = <marshmallow.missing>, hidden_keys: list[str] | marshmallow.utils._Missing = <marshmallow.missing>, button: str | None | marshmallow.utils._Missing = <marshmallow.missing>, buttonText: str | None | marshmallow.utils._Missing = <marshmallow.missing>, allowUnsavedLeave: bool | marshmallow.utils._Missing | None = <marshmallow.missing>, disableUnchanged: bool | marshmallow.utils._Missing | None = <marshmallow.missing>, footer: str | marshmallow.utils._Missing = <marshmallow.missing>, forceBrowser: bool | marshmallow.utils._Missing | None = <marshmallow.missing>, globalField: bool | marshmallow.utils._Missing | None = <marshmallow.missing>, readonly: bool | marshmallow.utils._Missing | None = <marshmallow.missing>, lang: str | None | marshmallow.utils._Missing = <marshmallow.missing>, resetText: str | marshmallow.utils._Missing | None = <marshmallow.missing>, connectionErrorMessage: str | marshmallow.utils._Missing = <marshmallow.missing>, undo: tim_common.markupmodels.UndoInfo | marshmallow.utils._Missing | None = <marshmallow.missing>, autoadd: bool | marshmallow.utils._Missing = <marshmallow.missing>, autoUpdateTables: bool | marshmallow.utils._Missing = True, creditField: str | marshmallow.utils._Missing = <marshmallow.missing>, defaultPoints: float | marshmallow.utils._Missing = <marshmallow.missing>, failGrade: str | marshmallow.utils._Missing = <marshmallow.missing>, fieldhelper: bool | marshmallow.utils._Missing = <marshmallow.missing>, gradeField: str | marshmallow.utils._Missing = <marshmallow.missing>, peerReviewField: str | marshmallow.utils._Missing = <marshmallow.missing>, gradingScale: dict[typing.Any, typing.Any] | marshmallow.utils._Missing = <marshmallow.missing>, group: str | marshmallow.utils._Missing = <marshmallow.missing>, groups: list[str] | marshmallow.utils._Missing = <marshmallow.missing>, includeUsers: timApp.util.get_fields.MembershipFilter | marshmallow.utils._Missing = <MembershipFilter.Current: 'current'>, selectIncludeUsers: bool = False, paramFields: list[str] | marshmallow.utils._Missing = <marshmallow.missing>, preprogram: str | marshmallow.utils._Missing = <marshmallow.missing>, program: str | marshmallow.utils._Missing = <marshmallow.missing>, overrideGrade: bool = False, canOverwritePoints: bool = False, confirmText: str | marshmallow.utils._Missing = <marshmallow.missing>, timeout: int | marshmallow.utils._Missing = <marshmallow.missing>, updateFields: list[str] | marshmallow.utils._Missing = <marshmallow.missing>, nextRunner: str | marshmallow.utils._Missing = <marshmallow.missing>, timeZoneDiff: int | marshmallow.utils._Missing = <marshmallow.missing>, peerReview: bool | marshmallow.utils._Missing = <marshmallow.missing>)[source]#

Bases: tim_common.markupmodels.GenericMarkupModel

autoUpdateTables: bool | marshmallow.utils._Missing = True#
autoadd: bool | marshmallow.utils._Missing = <marshmallow.missing>#
canOverwritePoints: bool = False#
confirmText: str | marshmallow.utils._Missing = <marshmallow.missing>#
creditField: str | marshmallow.utils._Missing = <marshmallow.missing>#
defaultPoints: float | marshmallow.utils._Missing = <marshmallow.missing>#
failGrade: str | marshmallow.utils._Missing = <marshmallow.missing>#
fieldhelper: bool | marshmallow.utils._Missing = <marshmallow.missing>#
fields: list[str] | marshmallow.utils._Missing = <marshmallow.missing>#
gradeField: str | marshmallow.utils._Missing = <marshmallow.missing>#
gradingScale: dict[Any, Any] | marshmallow.utils._Missing = <marshmallow.missing>#
group: str | marshmallow.utils._Missing = <marshmallow.missing>#
groups: list[str] | marshmallow.utils._Missing = <marshmallow.missing>#
includeUsers: timApp.util.get_fields.MembershipFilter | marshmallow.utils._Missing = 'current'#
nextRunner: str | marshmallow.utils._Missing = <marshmallow.missing>#
overrideGrade: bool = False#
paramFields: list[str] | marshmallow.utils._Missing = <marshmallow.missing>#
peerReview: bool | marshmallow.utils._Missing = <marshmallow.missing>#
peerReviewField: str | marshmallow.utils._Missing = <marshmallow.missing>#
postprogram: str | marshmallow.utils._Missing = <marshmallow.missing>#
preprogram: str | marshmallow.utils._Missing = <marshmallow.missing>#
program: str | marshmallow.utils._Missing = <marshmallow.missing>#
selectIncludeUsers: bool = False#
showInView: bool = False#
timeZoneDiff: int | marshmallow.utils._Missing = <marshmallow.missing>#
timeout: int | marshmallow.utils._Missing = <marshmallow.missing>#
updateFields: list[str] | marshmallow.utils._Missing = <marshmallow.missing>#
validate_schema(data: dict, **_: dict) None[source]#
class timApp.answer.routes.JsrunnerGroups[source]#

Bases: TypedDict

add: dict[str, list[int]]#
remove: dict[str, list[int]]#
set: dict[str, list[int]]#
class timApp.answer.routes.RefFrom(docId: int, par: str)[source]#

Bases: object

docId: int#
par: str#
class timApp.answer.routes.UserFieldEntry[source]#

Bases: TypedDict

fields: dict[str, str]#
user: int#
class timApp.answer.routes.UserGroupMembersState(before: set[int], after: set[int])[source]#

Bases: object

after: set[int]#
before: set[int]#
timApp.answer.routes.call_plugin_answer_and_parse(answer_call_data: dict, plugintype: str) dict[source]#
timApp.answer.routes.check_answerupload_file_accesses(filelist: list[str], curr_user: timApp.user.user.User) list[timApp.answer.answer_models.AnswerUpload][source]#

Checks user’s access to uploads by checking access to the answers associated with them

timApp.answer.routes.create_missing_users(users: list[timApp.plugin.importdata.importData.MissingUser]) tuple[list[timApp.answer.routes.UserFieldEntry], list[timApp.user.user.User]][source]#
timApp.answer.routes.delete_answer(answer_id: int) flask.wrappers.Response[source]#

Deletes an answer.

This does not completely delete the answer but only removes user associations from it, so it is no longer visible in TIM.

timApp.answer.routes.delete_answer_collab(answer_id: int, user_id: int) flask.wrappers.Response[source]#

Deletes an answer collaborator.

timApp.answer.routes.ensure_grade_and_credit(prg: str, flds: list[str]) None[source]#
timApp.answer.routes.export_answers(doc_path: str) flask.wrappers.Response[source]#
timApp.answer.routes.find_tim_vars(plugin: timApp.plugin.plugin.Plugin) dict[source]#
timApp.answer.routes.get_all_answers_as_list(task_ids: list[timApp.plugin.taskid.TaskId], options: timApp.answer.answers.AllAnswersOptions) list[str][source]#
timApp.answer.routes.get_all_answers_list_plain(task_ids: list[timApp.plugin.taskid.TaskId], options: timApp.answer.answers.AllAnswersOptions) flask.wrappers.Response[source]#
timApp.answer.routes.get_all_answers_plain(task_id: str, options: timApp.answer.answers.AllAnswersOptions) flask.wrappers.Response[source]#
timApp.answer.routes.get_answers(task_id: str, user_id: int) flask.wrappers.Response[source]#
timApp.answer.routes.get_answers_for_tasks(tasks: list[str], user_id: int) flask.wrappers.Response[source]#

Route for getting latest valid answers for given user and list of tasks

Returns

{“answers”: {taskID: Answer}, “userId”: user_id}

timApp.answer.routes.get_document_answers(doc_path: str, options: timApp.answer.answers.AllAnswersOptions) flask.wrappers.Response[source]#
timApp.answer.routes.get_global_answers(parsed_task_ids: dict[str, timApp.plugin.taskid.TaskId]) list[timApp.answer.answer.Answer][source]#
timApp.answer.routes.get_globals_for_tasks(task_ids: list[timApp.plugin.taskid.TaskId], answer_map: dict[str, dict]) None[source]#
timApp.answer.routes.get_hidden_name(user_id: str) str[source]#
timApp.answer.routes.get_iframehtml(plugintype: str, task_id_ext: str, user_id: int) flask.wrappers.Response[source]#
timApp.answer.routes.get_iframehtml_answer(plugintype: str, task_id_ext: str, user_id: int, answer_id: Optional[int] = None) flask.wrappers.Response[source]#
timApp.answer.routes.get_iframehtml_answer_impl(plugintype: str, task_id_ext: str, user_id: int, answer_id: Optional[int] = None) flask.wrappers.Response[source]#

Gets the HTML to be used in iframe.

Parameters
  • plugintype – plugin type

  • task_id_ext – task id

  • user_id – the user whose information to get

  • answer_id – answer id from answer browser

Returns

HTML to be used in iframe

timApp.answer.routes.get_jsframe_data(task_id: str, user_id: str) flask.wrappers.Response[source]#

TODO: check proper rights

timApp.answer.routes.get_plug_vals(doc: timApp.document.docinfo.DocInfo, tid: timApp.plugin.taskid.TaskId, user_ctx: timApp.document.usercontext.UserContext, view_ctx: timApp.document.viewcontext.ViewContext) timApp.answer.routes.FieldInfo | None[source]#
timApp.answer.routes.get_postanswer_plugin_etc(d: timApp.document.docinfo.DocInfo, tid: timApp.plugin.taskid.TaskId, answer_browser_data: dict, curr_user: timApp.user.user.User, ctx_user: timApp.user.user.User | None, urlmacros: tuple[tuple[str, str], ...], users: list[timApp.user.user.User] | None, other_session_users: list[timApp.user.user.User], origin: timApp.document.viewcontext.OriginInfo | None, force_answer: bool) tuple[timApp.auth.accesshelper.TaskAccessVerification, timApp.answer.answers.ExistingAnswersInfo, list[timApp.user.user.User], bool, bool, bool][source]#
timApp.answer.routes.get_state(user_id: int, answer_id: int | None = None, par_id: str | None = None, doc_id: int | None = None, review: bool = False, task_id: str | None = None, answernr: int | None = None, ask_new: bool | None = False) flask.wrappers.Response[source]#
timApp.answer.routes.get_task_info(task_id) flask.wrappers.Response[source]#
timApp.answer.routes.get_task_users(task_id: str) flask.wrappers.Response[source]#
timApp.answer.routes.get_useranswers_for_task(user: timApp.user.user.User, task_ids: list[timApp.plugin.taskid.TaskId], answer_map: dict[str, dict]) list[timApp.answer.answer.Answer][source]#

Performs a query for latest valid answers by given user for given task Similar to timApp.plugin.pluginControl.get_answers() but without counting

Parameters
  • user – user

  • task_ids – tasks to be queried

  • answer_map – a dict where to add each taskID: Answer

Returns

{taskID: Answer}

timApp.answer.routes.handle_jsrunner_groups(groupdata: timApp.answer.routes.JsrunnerGroups | None, curr_user: timApp.user.user.User) None[source]#
timApp.answer.routes.handle_points_ref(answerdata: dict[str, Any], curr_user: timApp.user.user.User, d: timApp.document.docinfo.DocInfo, ptype: timApp.plugin.plugintype.PluginTypeBase, tid: timApp.plugin.taskid.TaskId) dict[source]#
timApp.answer.routes.hide_points(a: timApp.answer.answer.Answer | dict) dict[source]#
timApp.answer.routes.hide_points_modifier(a: timApp.answer.answer.Answer | dict) dict[source]#
timApp.answer.routes.import_answers(exported_answers: list[timApp.answer.exportedanswer.ExportedAnswer], allow_missing_users: bool = False, match_email_case: bool = True, doc_map: dict[str, str] = Field(name='doc_map',type=dict[str, str],default=<dataclasses._MISSING_TYPE object>,default_factory=<class 'dict'>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD)) flask.wrappers.Response[source]#
timApp.answer.routes.maybe_hide_name(d: timApp.document.docinfo.DocInfo, u: timApp.user.user.User, model_u: timApp.user.user.User | None) None[source]#
timApp.answer.routes.multisendemail(doc_id: int, rcpt: str, subject: str, msg: str, bccme: bool = False, replyall: bool = False) flask.wrappers.Response[source]#
timApp.answer.routes.points_to_float(points: str | float | None) float | None[source]#
timApp.answer.routes.post_answer(plugintype: str, task_id_ext: str, input: typing.Union[dict[str, typing.Any], list[typing.Any], int, float, str], abData: dict[str, typing.Any] = Field(name='abData',type=dict[str, typing.Any],default=<dataclasses._MISSING_TYPE object>,default_factory=<class 'dict'>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD), options: dict[str, typing.Any] = Field(name='options',type=dict[str, typing.Any],default=<dataclasses._MISSING_TYPE object>,default_factory=<class 'dict'>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD)) flask.wrappers.Response[source]#

Saves the answer submitted by user for a plugin in the database.

Parameters
  • plugintype – The type of the plugin, e.g. csPlugin. TODO: No longer needed because it is checked from the document block’s plugin attribute.

  • task_id_ext – The extended task id of the form “22.palidrome.par_id”.

  • input – Answer data to save

  • options – Options to apply for answer saving

  • abData – Data applied from answer browser

timApp.answer.routes.post_answer_impl(task_id_ext: str, answerdata: Union[dict[str, Any], list[Any], int, float, str], answer_browser_data: dict, answer_options: dict, curr_user: timApp.user.user.User, urlmacros: tuple[tuple[str, str], ...], other_session_users: list[timApp.user.user.User], origin: timApp.document.viewcontext.OriginInfo | None) timApp.answer.routes.AnswerRouteResult[source]#
timApp.answer.routes.preprocess_jsrunner_answer(answerdata: dict[str, Any], curr_user: timApp.user.user.User, d: timApp.document.docinfo.DocInfo, plugin: timApp.plugin.plugin.Plugin) None[source]#

Executed before the actual jsrunner answer route is called. This is required to fetch the requested data from the database.

timApp.answer.routes.rename_answers(old_name: str, new_name: str, doc_path: str) flask.wrappers.Response[source]#
timApp.answer.routes.save_fields(jsonresp: timApp.answer.routes.FieldSaveRequest, curr_user: timApp.user.user.User, current_doc: Optional[timApp.document.docinfo.DocInfo] = None, allow_non_teacher: bool = False, add_users_to_group: Optional[str] = None, overwrite_previous_points: bool = False, pr_data: Optional[str] = None) timApp.answer.routes.FieldSaveResult[source]#
timApp.answer.routes.save_points(answer_id: int, user_id: int, points: Optional[Union[float, str]] = None) flask.wrappers.Response[source]#
timApp.answer.routes.save_validity(answer_id: int, valid: bool) flask.wrappers.Response[source]#
timApp.answer.routes.should_hide_name(d: timApp.document.docinfo.DocInfo, user: timApp.user.user.User, model_u: timApp.user.user.User | None) bool[source]#
timApp.answer.routes.unlock_task(task_id: str) flask.wrappers.Response[source]#
timApp.answer.routes.verify_answer_access(answer_id: int, user_id: int, view_ctx: timApp.document.viewcontext.ViewContext, require_teacher_if_not_own: bool = False, required_task_access_level: timApp.plugin.taskid.TaskIdAccess = TaskIdAccess.ReadOnly, allow_grace_period: bool = False) tuple[timApp.answer.answer.Answer, int][source]#
timApp.answer.routes.verify_user_create_right(curr_user: timApp.user.user.User) None[source]#

Module contents#