Merge remote-tracking branch 'origin/data_migrations' into treenode_editor
This commit is contained in:
		
						commit
						e4818d28ea
					
				
					 4 changed files with 102 additions and 303 deletions
				
			
		|  | @ -8,98 +8,96 @@ from django.utils.encoding import force_text | ||||||
| from .models import Problem, Cislo, Reseni, Nastaveni, Rocnik, Soustredeni | from .models import Problem, Cislo, Reseni, Nastaveni, Rocnik, Soustredeni | ||||||
| #from .models import VysledkyZaCislo, VysledkyKCisluZaRocnik, VysledkyKCisluOdjakziva | #from .models import VysledkyZaCislo, VysledkyKCisluZaRocnik, VysledkyKCisluOdjakziva | ||||||
| from .ovvpfile import OvvpFile | from .ovvpfile import OvvpFile | ||||||
|  | from seminar import views | ||||||
| 
 | 
 | ||||||
| class ExportIndexView(generic.View): | class ExportIndexView(generic.View): | ||||||
|     def get(self, request): | 	def get(self, request): | ||||||
|  | 		ls = [] | ||||||
|  | 		for r in Rocnik.objects.filter(exportovat = True): | ||||||
|  | 	    		url = reverse('seminar_export_rocnik', kwargs={'prvni_rok': r.prvni_rok}) | ||||||
|  | 	    		ls.append(url.split('/')[-1]) | ||||||
|  | 		for s in Soustredeni.objects.filter(exportovat = True): | ||||||
|  | 			url = reverse('seminar_export_sous', kwargs={'datum_zacatku': s.datum_zacatku.isoformat()}) | ||||||
|  | 			ls.append(url.split('/')[-1]) | ||||||
| 
 | 
 | ||||||
|         ls = [] | 		return HttpResponse('\n'.join(ls) + '\n', content_type='text/plain; charset=utf-8') | ||||||
|         for r in Rocnik.objects.filter(exportovat = True): |  | ||||||
|             url = reverse('seminar_export_rocnik', kwargs={'prvni_rok': r.prvni_rok}) |  | ||||||
|             ls.append(url.split('/')[-1]) |  | ||||||
|         for s in Soustredeni.objects.filter(exportovat = True): |  | ||||||
|             url = reverse('seminar_export_sous', kwargs={'datum_zacatku': s.datum_zacatku.isoformat()}) |  | ||||||
|             ls.append(url.split('/')[-1]) |  | ||||||
| 
 |  | ||||||
|         return HttpResponse('\n'.join(ls) + '\n', content_type='text/plain; charset=utf-8') |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def default_ovvpfile(event, rocnik): | def default_ovvpfile(event, rocnik): | ||||||
|     of = OvvpFile() | 	of = OvvpFile() | ||||||
|     of.headers['version'] = '1' | 	of.headers['version'] = '1' | ||||||
|     of.headers['event'] = event | 	of.headers['event'] = event | ||||||
|     of.headers['year'] = force_text(rocnik.prvni_rok) | 	of.headers['year'] = force_text(rocnik.prvni_rok) | ||||||
|     of.headers['date'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") | 	of.headers['date'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") | ||||||
|     of.headers['id-scope'] = 'mam' | 	of.headers['id-scope'] = 'mam' | ||||||
|     of.headers['id-generation'] = '1' | 	of.headers['id-generation'] = '1' | ||||||
|     return of | 	return of | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class ExportSousView(generic.View): | class ExportSousView(generic.View): | ||||||
| 
 | 
 | ||||||
|     def get(self, request, datum_zacatku=None): | 	def get(self, request, datum_zacatku=None): | ||||||
|         try: | 		try: | ||||||
|             dz = django.utils.dateparse.parse_date(datum_zacatku) | 		    dz = django.utils.dateparse.parse_date(datum_zacatku) | ||||||
|         except: | 		except: | ||||||
|             dz = None | 		    dz = None | ||||||
|         if dz is None: | 		if dz is None: | ||||||
|             raise django.http.Http404() | 		    raise django.http.Http404() | ||||||
| 
 | 
 | ||||||
|         s = get_object_or_404(Soustredeni, datum_zacatku=dz, exportovat=True) | 		s = get_object_or_404(Soustredeni, datum_zacatku=dz, exportovat=True) | ||||||
| 
 | 
 | ||||||
|         akce = {Soustredeni.TYP_JARNI: 'MaM.sous.jaro', | 		akce = {Soustredeni.TYP_JARNI: 'MaM.sous.jaro', | ||||||
|                 Soustredeni.TYP_PODZIMNI: 'MaM.sous.podzim', | 			Soustredeni.TYP_PODZIMNI: 'MaM.sous.podzim', | ||||||
|                 Soustredeni.TYP_VIKEND: 'MaM.vikend', | 			Soustredeni.TYP_VIKEND: 'MaM.vikend', | ||||||
|                 }[s.typ] | 			}[s.typ] | ||||||
| 
 |  | ||||||
|         of = default_ovvpfile(akce, s.rocnik) |  | ||||||
|         of.headers['x-event-begin'] = s.datum_zacatku.isoformat() |  | ||||||
|         of.headers['x-event-end'] = s.datum_konce.isoformat() |  | ||||||
|         of.headers['x-event-location'] = s.misto |  | ||||||
|         of.headers['comment'] = u'MaM-Web export ucastniku soustredeni v {x-event-location} od {x-event-begin} do {x-event-end}'.format(**of.headers) |  | ||||||
|         of.columns = ['id', 'name', 'surname', 'gender', 'email', 'end-year', 'school', 'school-name'] |  | ||||||
|           |  | ||||||
|         for u in s.ucastnici.all(): |  | ||||||
|             of.rows.append(u.export_row()) |  | ||||||
|          |  | ||||||
|         return of.to_HttpResponse() |  | ||||||
|          |  | ||||||
| 
 | 
 | ||||||
|  | 		of = default_ovvpfile(akce, s.rocnik) | ||||||
|  | 		of.headers['x-event-begin'] = s.datum_zacatku.isoformat() | ||||||
|  | 		of.headers['x-event-end'] = s.datum_konce.isoformat() | ||||||
|  | 		of.headers['x-event-location'] = s.misto | ||||||
|  | 		of.headers['comment'] = u'MaM-Web export ucastniku soustredeni v {x-event-location} od {x-event-begin} do {x-event-end}'.format(**of.headers) | ||||||
|  | 		of.columns = ['id', 'name', 'surname', 'gender', 'email', 'end-year', 'school', 'school-name'] | ||||||
|  | 	  | ||||||
|  | 		for u in s.ucastnici.all(): | ||||||
|  | 			of.rows.append(u.export_row()) | ||||||
|  | 	 | ||||||
|  | 		return of.to_HttpResponse() | ||||||
|  | 	 | ||||||
|  | # POZOR! Předělání na nový model neotestováno v reálu (ale zase jen drobné změny) | ||||||
| class ExportRocnikView(generic.View): | class ExportRocnikView(generic.View): | ||||||
| 
 | 
 | ||||||
|     def get(self, request, prvni_rok=None): | 	def get(self, request, prvni_rok=None): | ||||||
|         try: | 		try: | ||||||
|             pr = int(prvni_rok) | 		    pr = int(prvni_rok) | ||||||
|         except: | 		except: | ||||||
|             pr = None | 		    pr = None | ||||||
|         if pr is None: | 		if pr is None: | ||||||
|             raise django.http.Http404() | 		    raise django.http.Http404() | ||||||
| 
 | 
 | ||||||
|         rocnik = get_object_or_404(Rocnik, prvni_rok=pr, exportovat=True) | 		rocnik = get_object_or_404(Rocnik, prvni_rok=pr, exportovat=True) | ||||||
|         cislo = rocnik.posledni_zverejnena_vysledkovka_cislo() | 		cislo = rocnik.posledni_zverejnena_vysledkovka_cislo() | ||||||
|         vysledky = VysledkyKCisluZaRocnik.objects.filter(cislo = cislo).select_related("resitel").order_by('-body').all() | 		resitele = views.aktivniResitele(cislo.rocnik.rocnik, cislo.poradi, True) | ||||||
|  | 		slovnik_body = views.secti_body_za_rocnik(cislo, resitele) | ||||||
|  | 		_, setrizeni_resitele, setrizene_body = views.setrid_resitele_a_body(slovnik_body) | ||||||
| 
 | 
 | ||||||
|         of = default_ovvpfile('MaM.rocnik', rocnik) | 		of = default_ovvpfile('MaM.rocnik', rocnik) | ||||||
|         of.headers['comment'] = u'MaM-Web export aktivnich resitelu rocniku {rocnik} do cisla {cislo}'.format( | 		of.headers['comment'] = u'MaM-Web export aktivnich resitelu rocniku {rocnik} do cisla {cislo}'.format(rocnik=rocnik, cislo=cislo) | ||||||
|                 rocnik=rocnik, cislo=cislo) | 		of.columns = ['id', 'name', 'surname', 'gender', 'born', 'email', 'end-year', | ||||||
|         of.columns = ['id', 'name', 'surname', 'gender', 'born', 'email', 'end-year', | 			'street', 'town', 'postcode', 'country', 'spam-flag', 'spam-date', | ||||||
|                 'street', 'town', 'postcode', 'country', 'spam-flag', 'spam-date', | 			'school', 'school-name', 'points', 'rank',] | ||||||
|                 'school', 'school-name', 'points', 'rank',] | 	 | ||||||
|           | 		# počítání pořadí řešitelů  | ||||||
|         posledni_body = 100000 | 		posledni_body = 100000 | ||||||
|         posledni_poradi = 0 | 		posledni_poradi = 0 | ||||||
|         for vi in range(len(vysledky)): | 		for i in range(len(setrizeni_resitele)): | ||||||
| 
 | 			rd = setrizeni_resitele[i].export_row() | ||||||
|             v = vysledky[vi] |  | ||||||
|             rd = v.resitel.export_row() |  | ||||||
| 
 |  | ||||||
|             if posledni_body > v.body: |  | ||||||
|                 posledni_body = v.body |  | ||||||
|                 posledni_poradi = vi + 1 |  | ||||||
|             rd['rank'] = posledni_poradi |  | ||||||
|             rd['points'] = v.body |  | ||||||
| 
 |  | ||||||
|             of.rows.append(rd) |  | ||||||
|          |  | ||||||
|         return of.to_HttpResponse() |  | ||||||
| 
 | 
 | ||||||
|  | 			if posledni_body > body[i]: | ||||||
|  | 				posledni_body = body[i] | ||||||
|  | 				posledni_poradi = i + 1 | ||||||
|  | 			rd['rank'] = posledni_poradi | ||||||
|  | 			rd['points'] = body[i] | ||||||
| 
 | 
 | ||||||
|  | 			of.rows.append(rd) | ||||||
|  | 	 | ||||||
|  | 		return of.to_HttpResponse() | ||||||
|  |  | ||||||
|  | @ -94,17 +94,9 @@ urlpatterns = [ | ||||||
| 		staff_member_required(views.StavDatabazeView), name='stav_databaze'), | 		staff_member_required(views.StavDatabazeView), name='stav_databaze'), | ||||||
| 	path('cislo/<int:rocnik>.<int:cislo>/obalkovani', | 	path('cislo/<int:rocnik>.<int:cislo>/obalkovani', | ||||||
| 		staff_member_required(views.ObalkovaniView.as_view()), name='seminar_cislo_resitel_obalkovani'), | 		staff_member_required(views.ObalkovaniView.as_view()), name='seminar_cislo_resitel_obalkovani'), | ||||||
| 	path('cislo/<int:rocnik>.<int:cislo>/tex-download.json', |  | ||||||
| 		staff_member_required(views.texDownloadView), name='seminar_tex_download'), |  | ||||||
| 	path('soustredeni/<int:soustredeni>/obalky.pdf', | 	path('soustredeni/<int:soustredeni>/obalky.pdf', | ||||||
| 		staff_member_required(views.soustredeniObalkyView), name='seminar_soustredeni_obalky'), | 		staff_member_required(views.soustredeniObalkyView), name='seminar_soustredeni_obalky'), | ||||||
| 
 | 
 | ||||||
| 	path('tex-upload/login/', views.TeXUploadLoginView, name='seminar_login'), |  | ||||||
| 	path( |  | ||||||
| 		'tex-upload/', |  | ||||||
| 		staff_member_required(views.texUploadView), |  | ||||||
| 		name='seminar_tex_upload' |  | ||||||
| 	), |  | ||||||
| 	path('org/vloz_body/<int:tema>/', | 	path('org/vloz_body/<int:tema>/', | ||||||
| 		staff_member_required(views.VlozBodyView.as_view()),name='seminar_org_vlozbody'), | 		staff_member_required(views.VlozBodyView.as_view()),name='seminar_org_vlozbody'), | ||||||
| 	path('auth/prihlaska/',views.prihlaskaView, name='seminar_prihlaska'), | 	path('auth/prihlaska/',views.prihlaskaView, name='seminar_prihlaska'), | ||||||
|  |  | ||||||
|  | @ -49,40 +49,40 @@ def seznam_problemu(): | ||||||
| 
 | 
 | ||||||
| 	# Pomocna fce k formatovani problemovych hlasek | 	# Pomocna fce k formatovani problemovych hlasek | ||||||
| 	def prb(cls, msg, objs=None): | 	def prb(cls, msg, objs=None): | ||||||
| 		s = u'<b>%s:</b> %s' % (cls.__name__, msg) | 		s = '<b>%s:</b> %s' % (cls.__name__, msg) | ||||||
| 		if objs: | 		if objs: | ||||||
| 			s += u' [' | 			s += ' [' | ||||||
| 			for o in objs: | 			for o in objs: | ||||||
| 				try: | 				try: | ||||||
| 					url = o.admin_url() | 					url = o.admin_url() | ||||||
| 				except: | 				except: | ||||||
| 					url = None | 					url = None | ||||||
| 				if url: | 				if url: | ||||||
| 					s += u'<a href="%s">%s</a>, ' % (url, o.pk, ) | 					s += '<a href="%s">%s</a>, ' % (url, o.pk, ) | ||||||
| 				else: | 				else: | ||||||
| 					s += u'%s, ' % (o.pk, ) | 					s += '%s, ' % (o.pk, ) | ||||||
| 			s = s[:-2] + u']' | 			s = s[:-2] + ']' | ||||||
| 		problemy.append(s) | 		problemy.append(s) | ||||||
| 
 | 
 | ||||||
| 	# Duplicita jmen | 	# Duplicita jmen | ||||||
| 	jmena = {} | 	jmena = {} | ||||||
| 	for r in m.Resitel.objects.all(): | 	for r in m.Resitel.objects.all(): | ||||||
| 		j = r.plne_jmeno() | 		j = r.osoba.plne_jmeno() | ||||||
| 		if j not in jmena: | 		if j not in jmena: | ||||||
| 			jmena[j] = [] | 			jmena[j] = [] | ||||||
| 		jmena[j].append(r) | 		jmena[j].append(r) | ||||||
| 	for j in jmena: | 	for j in jmena: | ||||||
| 		if len(jmena[j]) > 1: | 		if len(jmena[j]) > 1: | ||||||
| 			prb(m.Resitel, u'Duplicitní jméno "%s"' % (j, ), jmena[j]) | 			prb(m.Resitel, 'Duplicitní jméno "%s"' % (j, ), jmena[j]) | ||||||
| 
 | 
 | ||||||
| 	# Data maturity a narození | 	# Data maturity a narození | ||||||
| 	for r in m.Resitel.objects.all(): | 	for r in m.Resitel.objects.all(): | ||||||
| 		if not r.rok_maturity: | 		if not r.rok_maturity: | ||||||
| 			prb(m.Resitel, u'Neznámý rok maturity', [r]) | 			prb(m.Resitel, 'Neznámý rok maturity', [r]) | ||||||
| 		if r.rok_maturity and (r.rok_maturity < 1990 or r.rok_maturity > datetime.date.today().year + 10): | 		if r.rok_maturity and (r.rok_maturity < 1990 or r.rok_maturity > datetime.date.today().year + 10): | ||||||
| 			prb(m.Resitel, u'Podezřelé datum maturity', [r]) | 			prb(m.Resitel, 'Podezřelé datum maturity', [r]) | ||||||
| 		if r.datum_narozeni and (r.datum_narozeni.year < 1970 or r.datum_narozeni.year > datetime.date.today().year - 12): | 		if r.osoba.datum_narozeni and (r.osoba.datum_narozeni.year < 1970 or r.osoba.datum_narozeni.year > datetime.date.today().year - 12): | ||||||
| 			prb(m.Resitel, u'Podezřelé datum narození', [r]) | 			prb(m.Resitel, 'Podezřelé datum narození', [r]) | ||||||
| #        if not r.email: | #        if not r.email: | ||||||
| #            prb(Resitel, u'Neznámý email', [r]) | #            prb(Resitel, u'Neznámý email', [r]) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -645,6 +645,12 @@ class RadekVysledkovkyRocniku(object): | ||||||
| 		self.body_cisla_sezn = body_cisla_sezn | 		self.body_cisla_sezn = body_cisla_sezn | ||||||
| 		self.titul = resitel.get_titul(body_odjakziva) | 		self.titul = resitel.get_titul(body_odjakziva) | ||||||
| 
 | 
 | ||||||
|  | def setrid_resitele_a_body(slov_resitel_body): | ||||||
|  | 	setrizeni_resitele_id = [dvojice[0] for dvojice in slov_resitel_body] | ||||||
|  | 	setrizeni_resitele = [Resitel.objects.get(id=i) for i in setrizeni_resitele_id] | ||||||
|  | 	setrizene_body = [dvojice[1] for dvojice in slov_resitel_body] | ||||||
|  | 	return setrizeni_resitele_id, setrizeni_resitele, setrizene_body | ||||||
|  | 
 | ||||||
| def vysledkovka_rocniku(rocnik, jen_verejne=True): | def vysledkovka_rocniku(rocnik, jen_verejne=True): | ||||||
| 	""" Přebírá ročník (např. context["rocnik"]) a vrací výsledkovou listinu ve | 	""" Přebírá ročník (např. context["rocnik"]) a vrací výsledkovou listinu ve | ||||||
| 	formě vhodné pro šablonu "seminar/vysledkovka_rocniku.html" | 	formě vhodné pro šablonu "seminar/vysledkovka_rocniku.html" | ||||||
|  | @ -665,9 +671,7 @@ def vysledkovka_rocniku(rocnik, jen_verejne=True): | ||||||
| 	resitel_rocnikbody_sezn = secti_body_za_rocnik(rocnik, aktivni_resitele) | 	resitel_rocnikbody_sezn = secti_body_za_rocnik(rocnik, aktivni_resitele) | ||||||
| 	 | 	 | ||||||
| 	# setřídíme řešitele podle počtu bodů a získáme seznam s body od nejvyšších po nenižší | 	# setřídíme řešitele podle počtu bodů a získáme seznam s body od nejvyšších po nenižší | ||||||
| 	setrizeni_resitele_id = [dvojice[0] for dvojice in resitel_rocnikbody_sezn] | 	setrizeni_resitele_id, setrizeni_resitele, setrizene_body = setrid_resitele_a_body(resitel_rocnikbody_sezn) | ||||||
| 	setrizeni_resitele = [Resitel.objects.get(id=i) for i in setrizeni_resitele_id] |  | ||||||
| 	setrizene_body = [dvojice[1] for dvojice in resitel_rocnikbody_sezn] |  | ||||||
| 	poradi = sloupec_s_poradim(setrizene_body) | 	poradi = sloupec_s_poradim(setrizene_body) | ||||||
| 
 | 
 | ||||||
| 	# získáme body odjakživa | 	# získáme body odjakživa | ||||||
|  | @ -958,12 +962,13 @@ def resi_v_rocniku(rocnik, cislo=None): | ||||||
| 	return letosni_resitele.distinct() | 	return letosni_resitele.distinct() | ||||||
| 	 | 	 | ||||||
| 		 | 		 | ||||||
| def aktivniResitele(rocnik, cislo): | def aktivniResitele(rocnik, cislo, pouze_realni=False): | ||||||
| 	""" Vrací QuerySet aktivních řešitelů, což jsou ti, co ještě neodmaturovali | 	""" Vrací QuerySet aktivních řešitelů, což jsou ti, co ještě neodmaturovali | ||||||
| 	a letos něco poslali (anebo loni něco poslali, pokud jde o první tři čísla). | 	a letos něco poslali (anebo loni něco poslali, pokud jde o první tři čísla). | ||||||
| 	Parametry: | 	Parametry: | ||||||
| 		rocnik (typu int)	číslo ročníku, o který se jedná | 		rocnik (typu int)	číslo ročníku, o který se jedná | ||||||
| 		cislo (typu int)	pořadí čísla, o které se jedná | 		cislo (typu int)	pořadí čísla, o které se jedná | ||||||
|  | 		pouze_realni		jen řešitelé, kteří tento rok něco poslali | ||||||
| 
 | 
 | ||||||
| 	""" | 	""" | ||||||
| 	letos = Rocnik.objects.get(rocnik = rocnik) | 	letos = Rocnik.objects.get(rocnik = rocnik) | ||||||
|  | @ -979,6 +984,10 @@ def aktivniResitele(rocnik, cislo): | ||||||
| 	except ValueError: | 	except ValueError: | ||||||
|        		# pravděpodobně se jedná o číslo 7-8 |        		# pravděpodobně se jedná o číslo 7-8 | ||||||
| 		zacatek_rocniku = False | 		zacatek_rocniku = False | ||||||
|  | 	 | ||||||
|  | 	# nehledě na číslo chceme jen řešitele, kteří letos něco odevzdali | ||||||
|  | 	if pouze_realni: | ||||||
|  | 		zacatek_rocniku = False | ||||||
| 
 | 
 | ||||||
| 	if not zacatek_rocniku: | 	if not zacatek_rocniku: | ||||||
| 		return resi_v_rocniku(letos)	 | 		return resi_v_rocniku(letos)	 | ||||||
|  | @ -1123,8 +1132,8 @@ class ClankyResitelView(generic.ListView): | ||||||
| def StavDatabazeView(request): | def StavDatabazeView(request): | ||||||
| #	nastaveni = Nastaveni.objects.get() | #	nastaveni = Nastaveni.objects.get() | ||||||
| 	problemy = utils.seznam_problemu() | 	problemy = utils.seznam_problemu() | ||||||
| 	muzi = Resitel.objects.filter(pohlavi_muz=True) | 	muzi = Resitel.objects.filter(osoba__pohlavi_muz=True) | ||||||
| 	zeny = Resitel.objects.filter(pohlavi_muz=False) | 	zeny = Resitel.objects.filter(osoba__pohlavi_muz=False) | ||||||
| 	return render(request, 'seminar/stav_databaze.html', | 	return render(request, 'seminar/stav_databaze.html', | ||||||
| 			{ | 			{ | ||||||
| #				'nastaveni': nastaveni, | #				'nastaveni': nastaveni, | ||||||
|  | @ -1133,211 +1142,11 @@ def StavDatabazeView(request): | ||||||
| 				'resitele': Resitel.objects.all(), | 				'resitele': Resitel.objects.all(), | ||||||
| 				'muzi': muzi, | 				'muzi': muzi, | ||||||
| 				'zeny': zeny, | 				'zeny': zeny, | ||||||
| 				'jmena_muzu': utils.histogram([r.jmeno for r in muzi]), | 				'jmena_muzu': utils.histogram([r.osoba.jmeno for r in muzi]), | ||||||
| 				'jmena_zen': utils.histogram([r.jmeno for r in zeny]), | 				'jmena_zen': utils.histogram([r.osoba.jmeno for r in zeny]), | ||||||
| 			}) | 			}) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| @ensure_csrf_cookie |  | ||||||
| def TeXUploadLoginView(request): |  | ||||||
| 	"""Pro přihlášení při nahrávání z texu""" |  | ||||||
| 	q = request.POST |  | ||||||
| 	# nastavení cookie csrftoken |  | ||||||
| 	if not q: |  | ||||||
| 		return JsonResponse({"ok": 1}) |  | ||||||
| 
 |  | ||||||
| 	if "username" in q: |  | ||||||
| 		username = q["username"] |  | ||||||
| 		password = q["password"] |  | ||||||
| 		user = authenticate(username=username, password=password) |  | ||||||
| 		if user is not None and user.is_staff: |  | ||||||
| 			login(request, user) |  | ||||||
| 			return JsonResponse({"ok": 1}) |  | ||||||
| 		else: |  | ||||||
| 			return JsonResponse({"error": "Neplatné uživatelské jméno nebo heslo"}) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| @ensure_csrf_cookie |  | ||||||
| def texUploadView(request): |  | ||||||
| 
 |  | ||||||
| 	def uloz_soubory(files, rocnik, cislo): |  | ||||||
| 		for filename, f in files: |  | ||||||
| 			path = os.path.join( |  | ||||||
| 				settings.MEDIA_ROOT, |  | ||||||
| 				settings.CISLO_IMG_DIR, |  | ||||||
| 				rocnik, |  | ||||||
| 				cislo, |  | ||||||
| 				filename |  | ||||||
| 			) |  | ||||||
| 
 |  | ||||||
| 			adresar = os.path.dirname(path) |  | ||||||
| 			if not os.path.exists(adresar): |  | ||||||
| 				os.makedirs(adresar) |  | ||||||
| 
 |  | ||||||
| 			with open(path, "wb+") as fout: |  | ||||||
| 				for chunk in f.chunks(): |  | ||||||
| 					fout.write(chunk) |  | ||||||
| 
 |  | ||||||
| 	q = request.POST |  | ||||||
| 	# nastavení cookie csrftoken |  | ||||||
| 	if not q: |  | ||||||
| 		return JsonResponse({"ok": 1}) |  | ||||||
| 
 |  | ||||||
| 	# Odchytíme všechny výjimky a traceback pošleme v odpovědi |  | ||||||
| 	try: |  | ||||||
| 		meta = json.loads(q["meta"]) |  | ||||||
| 		html = q["html"] |  | ||||||
| 
 |  | ||||||
| 		if meta["typ"] in ["uloha", "serial", "reseni", "tema"]: |  | ||||||
| 
 |  | ||||||
| 			# Uložíme soubory |  | ||||||
| 			if meta["typ"] != "reseni": |  | ||||||
| 				c = meta["cislo"] |  | ||||||
| 			else: |  | ||||||
| 				# Řešení má nastavené číslo svojí úlohy, ale obrázky jsou |  | ||||||
| 				# ukládány do čísla, kde řešení vyšlo |  | ||||||
| 				c = meta["cislo_reseni"] |  | ||||||
| 
 |  | ||||||
| 			# Zjistíme typ ukládaného problému |  | ||||||
| 			typy = { |  | ||||||
| 				"uloha": Problem.TYP_ULOHA, |  | ||||||
| 				"serial": Problem.TYP_SERIAL, |  | ||||||
| 				"reseni": Problem.TYP_ULOHA, |  | ||||||
| 				"tema": Problem.TYP_TEMA, |  | ||||||
| 			} |  | ||||||
| 			problem_typ = typy[meta["typ"]] |  | ||||||
| 
 |  | ||||||
| 			# Pokud už problém existuje, vytáhneme jej z db a upravíme. |  | ||||||
| 			# Pokud neexistuje, vytvoříme jej jedině pokud je to vynucené. |  | ||||||
| 
 |  | ||||||
| 			# Pokud ročník/číslo ještě neexistuje, vyhodí to výjimku -> |  | ||||||
| 			# číslo/ročník se musí založit ručně v adminu. |  | ||||||
| 			rocnik = Rocnik.objects.get(rocnik=meta["rocnik"]) |  | ||||||
| 			cislo = Cislo.objects.get(rocnik=rocnik, cislo=meta["cislo"]) |  | ||||||
| 
 |  | ||||||
| 			existujici = Problem.objects.filter( |  | ||||||
| 				typ=problem_typ, |  | ||||||
| 				stav=Problem.STAV_ZADANY, |  | ||||||
| 				cislo_zadani=cislo, |  | ||||||
| 				kod=meta["kod"] |  | ||||||
| 			) |  | ||||||
| 
 |  | ||||||
| 			problem = None |  | ||||||
| 			if existujici: |  | ||||||
| 				problem = existujici[0] |  | ||||||
| 			elif "vytvor" in q: |  | ||||||
| 				# vytvoříme nový |  | ||||||
| 				problem = Problem( |  | ||||||
| 					typ=problem_typ, |  | ||||||
| 					stav=Problem.STAV_ZADANY, |  | ||||||
| 					kod=meta["kod"], |  | ||||||
| 					cislo_zadani=cislo |  | ||||||
| 				) |  | ||||||
| 			else: |  | ||||||
| 				return JsonResponse({ |  | ||||||
| 					"error": "Problém neexistuje: {} {}.{} kód {}".format( |  | ||||||
| 						meta["typ"], meta["rocnik"], meta["cislo"], meta["kod"] |  | ||||||
| 					) |  | ||||||
| 				}) |  | ||||||
| 
 |  | ||||||
| 			uloz_soubory(request.FILES.items(), meta["rocnik"], c) |  | ||||||
| 
 |  | ||||||
| 			if meta["typ"] == "reseni": |  | ||||||
| 				problem.text_reseni = html |  | ||||||
| 
 |  | ||||||
| 				# Pokud ročník/číslo ještě neexistuje, vyhodí to výjimku -> |  | ||||||
| 				# číslo/ročník se musí založit ručně v adminu |  | ||||||
| 				problem.cislo_reseni = Cislo.objects.get( |  | ||||||
| 					rocnik=rocnik, |  | ||||||
| 					cislo=meta["cislo_reseni"] |  | ||||||
| 				) |  | ||||||
| 				# při nahrávání řešení už původní zadání atd. neměníme |  | ||||||
| 			else: |  | ||||||
| 				problem.text_zadani = html |  | ||||||
| 				problem.nazev = meta["nazev"] |  | ||||||
| 				if meta["typ"] != "tema": |  | ||||||
| 					problem.body = meta["body"] |  | ||||||
| 
 |  | ||||||
| 			problem.save() |  | ||||||
| 			cislo.faze = cislo.FAZE_NAHRANO |  | ||||||
| 			cislo.save() |  | ||||||
| 
 |  | ||||||
| 			# Vrátíme id dané úlohy, aby se k ní dala případně připojit pohádka |  | ||||||
| 			return JsonResponse({"db_id": problem.id}) |  | ||||||
| 
 |  | ||||||
| 		elif meta["typ"] == "pohadka": |  | ||||||
| 			uloha = Problem.objects.get(typ=Problem.TYP_ULOHA, pk=meta["uloha"]) |  | ||||||
| 
 |  | ||||||
| 			# Pokud už příslušná pohádka existuje, jen ji upravíme |  | ||||||
| 			existujici = Pohadka.objects.filter(uloha=uloha, pred=meta["pred"]) |  | ||||||
| 			pohadka = None |  | ||||||
| 			if existujici: |  | ||||||
| 				pohadka = existujici[0] |  | ||||||
| 			else: |  | ||||||
| 				pohadka = Pohadka(uloha=uloha, pred=meta["pred"]) |  | ||||||
| 			pohadka.text = q["html"] |  | ||||||
| 			pohadka.save() |  | ||||||
| 
 |  | ||||||
| 			return JsonResponse({"db_id": pohadka.id}) |  | ||||||
| 
 |  | ||||||
| 	except Exception as e: |  | ||||||
| 		# Pošleme zpátky traceback, ať uživatel ví, v čem je problém |  | ||||||
| 		tb = "".join(traceback.format_exception(type(e), e, sys.exc_info()[2])) |  | ||||||
| 		return JsonResponse({"error": tb}) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def texDownloadView(request, rocnik, cislo): |  | ||||||
| 	"""View posílající JSON se zadanými a řešenými problémy pro založení čísla |  | ||||||
| 	""" |  | ||||||
| 	cislo = Cislo.objects.get(rocnik__rocnik=rocnik, cislo=cislo) |  | ||||||
| 	if cislo.faze == cislo.FAZE_NAHRANO: |  | ||||||
| 		# obsah byl nahrán z TeXu na web, už je příliš složitý |  | ||||||
| 		return JsonResponse( |  | ||||||
| 			{"error": "Obsah čísla už byl nahrán z TeXu na web."} |  | ||||||
| 		) |  | ||||||
| 
 |  | ||||||
| 	zadane = Problem.objects.filter( |  | ||||||
| 		cislo_zadani=cislo, |  | ||||||
| 		stav=Problem.STAV_ZADANY |  | ||||||
| 	) |  | ||||||
| 	resene = Problem.objects.filter( |  | ||||||
| 		cislo_reseni=cislo, |  | ||||||
| 		stav=Problem.STAV_ZADANY, |  | ||||||
| 		typ=Problem.TYP_ULOHA |  | ||||||
| 	) |  | ||||||
| 	pred_pohadky = Pohadka.objects.filter(uloha__cislo_zadani=cislo, pred=True) |  | ||||||
| 	po_pohadky = Pohadka.objects.filter(uloha__cislo_zadani=cislo, pred=False) |  | ||||||
| 
 |  | ||||||
| 	response = { |  | ||||||
| 		"zadane": [ |  | ||||||
| 			{ |  | ||||||
| 				"nazev": p.nazev, |  | ||||||
| 				"typ": p.typ, |  | ||||||
| 				"kod": p.kod, |  | ||||||
| 				"body": p.body, |  | ||||||
| 				"zadani": p.text_zadani, |  | ||||||
| 				"pred_pohadky": [x.text for x in pred_pohadky.filter(uloha=p)], |  | ||||||
| 				"po_pohadky": [x.text for x in po_pohadky.filter(uloha=p)], |  | ||||||
| 			} for p in zadane |  | ||||||
| 		], |  | ||||||
| 		"resene": [ |  | ||||||
| 			{ |  | ||||||
| 				"nazev": p.nazev, |  | ||||||
| 				"typ": p.typ, |  | ||||||
| 				"kod": p.kod, |  | ||||||
| 				"body": p.body, |  | ||||||
| 				"zadani": p.text_zadani, |  | ||||||
| 				"reseni": p.text_reseni, |  | ||||||
| 				"cislo_zadani": p.cislo_zadani.poradi, |  | ||||||
| 			} for p in resene |  | ||||||
| 		], |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	cislo.faze = Cislo.FAZE_TEX |  | ||||||
| 	cislo.save() |  | ||||||
| 	return JsonResponse(response) |  | ||||||
| 
 |  | ||||||
| class ResitelView(LoginRequiredMixin,generic.DetailView): | class ResitelView(LoginRequiredMixin,generic.DetailView): | ||||||
| 	model = Resitel | 	model = Resitel | ||||||
| 	template_name = 'seminar/resitel.html' | 	template_name = 'seminar/resitel.html' | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue