def survey_fill_new(request, user_id): if request.method == 'GET': try: # 가장 최근의 신입양식을 보여줌 form = Form.objects.filter(purpose='join_new', opened=True)[0] questions = Question.objects.filter(form=form).order_by('id') choices = Choice.objects.filter( question__in=questions).order_by('id') # 신입 가입을 위한 양식이 없는 경우 예외처리 except (ObjectDoesNotExist, IndexError): form = None questions = '' choices = '' context = { 'user_id': user_id, 'form': form, 'questions': questions, 'choices': choices, 'can_old_register': OperationScheme.can_old_register(), 'can_new_register': OperationScheme.can_new_register() } return render(request, 'surveys/survey_fill_new.html', context) elif request.method == 'POST': # 설문 완료 표시 user = User.objects.get(id=user_id) user.survey_done = True user.save() form = Form.objects.filter(purpose='join_new', opened=True)[0] form.users.add(user) form.save() questions = Question.objects.filter(form=form) # choice_many의 경우 여러 응답을 표시 for question in questions: if question.question_type == 'choice_many': all_answer = request.POST.getlist(question.question_text) answer = '' for text in all_answer: answer += text + ',' answer = answer[:-1] else: answer = request.POST.get(question.question_text) UserAnswer.objects.create(question=question, answer=answer, form=form, user=user) info = OperationScheme.latest() context = { 'purpose': form.purpose, 'bank': info.get_bank_display(), 'account': info.bank_account, 'boss_name': info.boss.name, 'new_pay': info.new_pay, 'old_pay': info.old_pay } return render(request, 'surveys/survey_fill_submit.html', context)
def clean(self): cleaned_data = super().clean() latest_os = OperationScheme.latest() partner = Partner.related_partner_activeuser(ActiveUser.objects.get(user=self.request.user, active_year=latest_os.current_year, active_semester=latest_os.current_semester)) participants = cleaned_data.get('participants') # 커피와 식사 모두 0인 경우 if cleaned_data.get('num_coffee') == 0 and cleaned_data.get('num_eat') == 0: raise forms.ValidationError('\'커모 횟수\'와 \'밥모 횟수\' 모두 0일 수 없습니다.') # 커모 수가 음수일 경우 elif cleaned_data.get('num_coffee') < 0: raise forms.ValidationError('\'커모 횟수\'가 음수일 수 없습니다.') # 밥모 수가 음수일 경우 elif cleaned_data.get('num_eat') < 0: raise forms.ValidationError('\'밥모 횟수\'가 음수일 수 없습니다.') # 아무도 선택하지 않았을때 elif participants is None: raise forms.ValidationError('짝모에 참가한 사람을 선택해주세요.') # 위짝지가 없으면 에러 발생 elif str(partner.up_partner.user.pk) not in participants: raise forms.ValidationError('짝모에는 위짝지가 반드시 포함되어야 합니다.') # 아래짝지가 없어도 에러 발생 elif len(participants) == 1: raise forms.ValidationError('짝모에는 아래짝지가 반드시 포함되어야 합니다.')
def get(self, request, pk): active_user = ActiveUser.objects.get(user__pk=pk) latest_os = OperationScheme.latest() pay = latest_os.new_pay if active_user.is_new else latest_os.old_pay return render(request, 'accounts/now_pay.html', context={'active_user': active_user, 'pay': pay})
def current_activeuser_set(): # 최신의 운영정보를 불러온다 latest_os = OperationScheme.latest() # 현재 학기, 연도에 대항하는 모든 짝지 객체를 불러온다 current_partners = Partner.objects \ .select_related('up_partner') \ .select_related('down_partner_1') \ .select_related('down_partner_2') \ .select_related('down_partner_3') \ .filter(partner_semester=latest_os.current_semester, partner_year=latest_os.current_year) # 만일 하나도 없다면 None을 반환한다 if not current_partners.exists(): return ActiveUser.objects.none() # 존재한다면 각 짝지객체에 속한 모든 ActiveUser객체들을 얻는다 activeusers = set() for partner in current_partners: activeusers = activeusers | partner.containing_active_users() activeuser_pks = [ activeuser.pk for activeuser in activeusers if activeuser is not None ] return ActiveUser.objects.select_related('user').filter( id__in=activeuser_pks)
def participate_meeting(request, pk): if request.method == 'POST': meeting = get_object_or_404(Meeting, pk=pk) # 가장 최신의 활동회원 객체를 불러온다. active_user = ActiveUser.objects.filter(user=request.user).latest() latest_os = OperationScheme.latest() # 상황이 어떻게 되었든 이번 년도,학기와 활동회원의 년도, 학기가 다르면 참여할 수 없다. if not (active_user.active_year, active_user.active_semester) == \ (latest_os.current_year, latest_os.current_semester): raise PermissionDenied('이번학기 활동회원만이 커모에 참가할 수 있습니다.') # 참가자가 꽉 차지 않은 경우 if meeting.can_participate(): # 참여/취소 여부를 boolean flag로 반환한다. flag = meeting.participate_or_not(active_user) messages.success(request, "참여했습니다") if flag else messages.success( request, "참여 취소되었습니다.") return redirect(meeting.cast()) else: # 참여자가 꽉 찬 경우 만일 참여 취소인 경우 참여 취소를 허용한다. if active_user in meeting.participants.all(): meeting.participants.remove(active_user) messages.success(request, "참여 취소되었습니다.") return redirect(meeting.cast())
def update_partner_score(self): from partners.models import Partner latest_os = OperationScheme.latest() # 현재 참여하고자 하는 active user의 가장 최신의 짝지 객체를 가져온다 for active_user in self.participants.all(): related_partner = Partner.related_partner_activeuser(active_user) if related_partner is None: # related partner가 없으면(운영자계정, 신입회원 등) 아무것도 하지 않는다 continue # 짝지 년도, 학기를 가장 최신의 운영정보 년도, 학기와 비교한다 if not (related_partner.partner_year == latest_os.current_year and related_partner.partner_semester == latest_os.current_semester): # 만일 다르다면 아무것도 하지 않는다. 신학기에 예전학기 짝지 정보를 불러온 것이기 때문이다. continue else: from meetings.models import CoffeeMeeting # 참여였을 경우 원하는 점수만큼(현재는 커피 한잔 점수) 올린다. 단 커모 개최자는 추가점수를 준다. if active_user == ActiveUser.objects.filter( user=self.author).latest(): related_partner.raise_score(latest_os.coffee_point + latest_os.extra_author_point) else: related_partner.raise_score(latest_os.coffee_point)
def raise_score(self, score): latest_os = OperationScheme.latest() if latest_os.semester_end: if now().date() > latest_os.semester_end: # 학기가 종료된 후에는 짝지점수를 올리면 안된다. return self.score += score self.save()
def dispatch(self, request, *args, **kwargs): if not OperationScheme.can_old_register(): # 아직 재가입 기간이 아니라면 해당 정보를 띄워준다 return render(request, 'accounts/cannot_register.html', context={'user': request.user}) else: # 재가입 기간이라면 그대로 진행한다. form_valid로 내려가겠지. return super(ActiveUserCreateView, self).dispatch(request, *args, **kwargs)
def dispatch(self, request, *args, **kwargs): if not OperationScheme.can_new_register(): return render(request, 'accounts/cannot_register.html', context={'user': request.user}) elif request.user.is_authenticated: return HttpResponse('왜 이미 로그인까지 하신분이 또 신입가입을 시도하십니까? 개발자를 괴롭히기 위함인가요?') else: # https://stackoverflow.com/questions/5433172/how-to-redirect-on-conditions-with-class-based-views-in-django-1-3 return super(UserCreateView, self).dispatch(request, *args, **kwargs)
def check_point(self): meetings = PartnerMeeting.objects.filter(partner=self.partner, created__year=now().year, created__month=now().month, created__day=now().day) latest_os = OperationScheme.latest() limit_coffee, limit_eat = latest_os.limit_coffee, latest_os.limit_eat coffee_score, eat_score = latest_os.coffee_point, latest_os.eat_point # 당일 짝모에서 커모, 밥모 수를 합한다. today_num_coffee = 0 today_num_eat = 0 for meeting in meetings: # 자기 자신의 인스턴스는 빼고 계산한다 if meeting != self: today_num_coffee += meeting.num_coffee today_num_eat += meeting.num_eat # 일일 커모 제한 확인 if limit_coffee <= today_num_coffee: coffee = 0 else: # 오늘 커모 횟수와 해당 커모 횟수의 합이 일일 제한보다 같거나 작으면 그대로 입력한다. if self.num_coffee <= (limit_coffee - today_num_coffee): coffee = self.num_coffee # 아닐시 일일 제한에서 남은 횟수만큼만 더해준다. else: coffee = limit_coffee - today_num_coffee # 일일 밥모 제한 확인 if limit_eat <= today_num_eat: eat = 0 else: # 오늘 밥모 횟수와 해당 밥모 횟수의 합이 일일 제한보다 같거나 작으면 그대로 입력한다. if self.num_eat <= (limit_eat - today_num_eat): eat = self.num_eat # 아닐시 일일 제한에서 남은 횟수만큼만 더해준다. else: eat = limit_eat - today_num_eat # 추가 점수 확인 extra = 0 num_partner = self.partner.down_partner_count() + 1 # 몇 인조인지 확인 if num_partner == self.num_down_partner + 1: if num_partner == 2: extra = latest_os.extra_2_point elif num_partner == 3: extra = latest_os.extra_3_point elif num_partner == 4: extra = latest_os.extra_4_point extra = extra * (coffee + eat) point = self.num_down_partner * (coffee_score * coffee + eat_score * eat) + extra self.point = point self.partner.raise_score(point)
def survey_fill(request, user_id, pk): if request.method == 'GET': form = Form.objects.get(id=pk) questions = Question.objects.filter(form=form).order_by('id') choices = Choice.objects.filter(question__in=questions).order_by('id') context = { 'form': form, 'questions': questions, 'choices': choices, 'can_old_register': OperationScheme.can_old_register(), 'can_new_register': OperationScheme.can_new_register() } return render(request, 'surveys/survey_fill.html', context) elif request.method == 'POST': user = User.objects.get(id=user_id) form = Form.objects.get(id=pk) questions = Question.objects.filter(form=form) for question in questions: if question.question_type == 'choice_many': all_answer = request.POST.getlist(question.question_text) answer = '' for text in all_answer: answer += text + ',' answer = answer[:-1] else: answer = request.POST.get(question.question_text) UserAnswer.objects.create(question=question, answer=answer, form=form, user=user) form.users.add(user) form.save() info = OperationScheme.latest() context = { 'purpose': form.purpose, 'bank': info.get_bank_display(), 'account': info.bank_account, 'boss_name': info.boss.name, 'new_pay': info.new_pay, 'old_pay': info.old_pay } return render(request, 'surveys/survey_fill_submit.html', context)
def get_queryset(self): latest_os = OperationScheme.latest() # 짝모와 커모 후기를 같이 보여준다. queryset = Instagram.objects \ .prefetch_related('photos') \ .select_related('author') \ .select_related('partnermeeting__partner') \ .select_related('coffeemeetingfeed') \ .prefetch_related('comments__author') \ .filter(created__gte=latest_os.semester_start) \ .order_by('-created', '-modified') return queryset
def dispatch(self, request, *args, **kwargs): self.cafe = get_object_or_404(Cafe, pk=self.kwargs['pk']) latest_active_user = ActiveUser.objects.select_related('user').filter( user=request.user).latest() latest_os = OperationScheme.latest() # 이번 년도,학기와 가장 마지막 등록한 activeuser의 등록 년도,학기가 일치해야 커모를 열 수 있다. # 그게 아니라면 예전에 등록하고 이번에는 등록하지 않은 회원인 것이다. if not (latest_os.current_year == latest_active_user.active_year and latest_os.current_semester == latest_active_user.active_semester): raise PermissionDenied('활동회원으로 등록하셔야 커모를 열 수 있습니다.') return super(CoffeeMeetingCreateView, self).dispatch(request, *args, **kwargs)
def form_valid(self, form): latest_os = OperationScheme.latest() user = self.request.user current_year, current_semester = latest_os.current_year, latest_os.current_semester form.instance.user = user form.instance.active_year = current_year form.instance.active_semester = current_semester if ActiveUser.objects.filter(user=user, active_year=current_year, active_semester=current_semester).exists(): # 현재년도,학기에 해당하는 유저가 활동회원 테이블에 존재하면 이미 재신청을 한 것이다. messages.error(self.request, _('이미 가입신청 하셨습니다.')) return self.form_invalid(form) else: return super(ActiveUserCreateView, self).form_valid(form)
def get_form_kwargs(self): # 해당 유저의 짝지 정보를 검색해 보낸다. form_kwargs = super().get_form_kwargs() latest_os = OperationScheme.latest() year, semester = latest_os.current_year, latest_os.current_semester partner_member = Partner.related_partner_activeuser(ActiveUser.objects.get(user=self.request.user, active_year=year, active_semester=semester )).containing_active_users() partner = [] for member in partner_member: # 실제 짝지 객체만 추가한다. if member is not None: partner.append(member) form_kwargs['participants'] = partner return form_kwargs
def get(self, request, **kwargs): # 유저가 속한 최신의 짝지 객체를 가져온다. try: latest_partner = Partner.related_partner_user(request.user) current_os = OperationScheme.latest() # 짝지 객체가 있는경우 짝지의 년도-학기를 현재 최신의 운영정보의 년도-학기와 비교한다 if latest_partner is None: raise Http404 # 다른경우 신학기 시작 후 기존회원의 옛날 짝지 데이터를 가져온 것이므로 에러 메세지를 띄우고 index로 보낸다. elif not ((current_os.current_year == latest_partner.partner_year) and ( current_os.current_semester == latest_partner.partner_semester)): raise Http404 else: return super(PartnerMeetingCreateView, self).get(self, request, **kwargs) except Http404: # 만일 짝지 객체가 없으면 신입회원이므로 에러 메세지를 띄우고 index로 보낸다. messages.error(request, '아직 짝지가 배정되지 않았습니다.') return redirect(reverse('core:index'))
def form_valid(self, form): instance = form.save() latest_os = OperationScheme.latest() year, semester = latest_os.current_year, latest_os.current_semester # 실제 참여한 사람으로만 참가자 목록을 업데이트한다. participants = [] for pk in self.request.POST.getlist('participants'): participants.append( ActiveUser.objects.get(user=User.objects.get(pk=pk), active_year=year, active_semester=semester)) instance.coffee_meeting.participants.set(participants) participants_len = len(participants) # 커모에 참여한 사람의 점수를 업데이트한다. if participants_len > 0: group = Partner.related_partner_activeuser(participants[0]) # 커모가 한 짝지 그룹으로만 이루어지지 않은 경우 점수를 올린다. if group is None or participants_len != len( set(participants).intersection( group.containing_active_users())): # 참가자가 4명 이상일 경우만 점수를 올린다. if participants_len >= 4: instance.coffee_meeting.update_partner_score() # 한 짝지 그룹으로만 이루어진 경우 짝모로 계산한다. 윗짝지가 존재해야한다. elif group.up_partner in participants: extra = 0 num_partner = group.down_partner_count() + 1 # 몇 인조인지 확인 if num_partner == participants_len: if num_partner == 2: extra = latest_os.extra_2_point elif num_partner == 3: extra = latest_os.extra_3_point elif num_partner == 4: extra = latest_os.extra_4_point # 아래짝지 수 * 커피점수(모두 모였으면 추가점수까지)만큼 점수를 부여한다. group.raise_score((participants_len - 1) * latest_os.coffee_point + extra) if self.request.FILES: for f in self.request.FILES.getlist('images'): feed_photo = FeedPhoto(instagram=instance, image=f) feed_photo.save() return super().form_valid(form)
def meeting_eat_validator(value): latest_os = OperationScheme.latest() if value > latest_os.limit_eat: raise ValidationError( _('일일 제한 밥모 횟수인 {}회 이하로 입력해주세요.'.format(latest_os.limit_eat)))
def entrypoint(request): """ 루트 url을 통해 처음 사이트로 들어온 경우 로그인 여부에 따라 분기한다.""" if request.user.is_authenticated: # 사용자가 로그인상태인 경우 if request.method == 'GET': # Meeting 객체들을 모두 불러와서 그 중 커모에 해당하는 객체는 빼준다. every_coffee_meetings = CoffeeMeeting.objects.all().values('meeting_ptr') official_and_educations = Meeting.objects \ .select_related('author') \ .select_related('officialmeeting') \ .select_related('coffeeeducation') \ .exclude(id__in=every_coffee_meetings) \ .order_by('-created')[:3] # 커모 중 최신 인스턴스 4개를 가져온다. coffee_meetings = CoffeeMeeting.objects \ .select_related('cafe') \ .select_related('author') \ .prefetch_related('photos') \ .prefetch_related('participants') \ .prefetch_related('cafe__photos') \ .all() \ .order_by('-meeting_date')[:4] # 짝모 역시 최신 인스턴스 4개를 가져온다 latest_partnermeetings = PartnerMeeting.objects \ .select_related('author') \ .select_related('partner') \ .select_related('partner__up_partner__user') \ .prefetch_related('photos') \ .all().order_by('-created')[:4] # 사진첩 carousel은 photo_album의 사진들만 8개까지 보여준다. latest_albumphotos = Photo.objects.all().order_by('-created')[:8] # 짝모 순위를 가져온다 partner_rank = Partner.objects \ .select_related('up_partner__user')\ .select_related('down_partner_1__user')\ .select_related('down_partner_2__user')\ .select_related('down_partner_3__user')\ .all().order_by('-score')[:4] current_os = OperationScheme.latest() # 최근의 짝지 객체를 갖고와서 아래짝지가 몇명인지 반환하고 기본 context를 정의한다. latest_partner = Partner.related_partner_user(request.user) context = {'user': request.user, 'official_meetings': official_and_educations, 'coffee_meetings': coffee_meetings, 'partner_meetings': latest_partnermeetings, 'latest_photos': latest_albumphotos, 'partner_rank': partner_rank } # latest_partner가 존재하고 이번 학기/년도와 짝지 학기/년도가 일치하면 최신의 짝지가 존재하는 것이다. if latest_partner is not None and ((current_os.current_year == latest_partner.partner_year) and (current_os.current_semester == latest_partner.partner_semester)): # 현재 사용자가 위짝지 여부, 아래짝지 명수, 각 아래짝지의 User객체를 넣어준다 up_partner = latest_partner.up_partner.user down_num = latest_partner.down_partner_count() if down_num == 1: down_partners = [latest_partner.down_partner_1.user] elif down_num == 2: down_partners = [latest_partner.down_partner_1.user, latest_partner.down_partner_2.user] elif down_num == 3: down_partners = [latest_partner.down_partner_1.user, latest_partner.down_partner_2.user, latest_partner.down_partner_3.user] context['partner_set'] = True context['is_up'] = up_partner == request.user context['down_num'] = down_num context['up_partner'] = up_partner context['down_partners'] = down_partners context['score'] = latest_partner.score return render(request, 'accounts/index.html', context) else: # 짝지 객체가 아예 없거나 현재 학기, 년도에 해당하는 짝지가 없다면 명시적으로 아직이라고 템플릿에 전달한다. context['partner_set'] = False return render(request, 'accounts/index.html', context) else: # 사용자가 인증되지 않았으면 index로 보낸다 return redirect('core:index')
def lazy_latest_os(): return OperationScheme.latest()
def __init__(self, model, admin_site): self.latest_os = OperationScheme.latest() super().__init__(model, admin_site)
def meeting_coffee_validator(value): latest_os = OperationScheme.latest() if value > latest_os.limit_coffee: raise ValidationError( _('일일 제한 커모 횟수인 {}회 이하로 입력해주세요.'.format(latest_os.limit_coffee)))
def export_users_excel(request, category): # 운영진인지 먼저 확인한다. if request.user.is_staff: latest_os = OperationScheme.latest() response = HttpResponse(content_type='application/ms-excel') wb = xlwt.Workbook(encoding='utf-8') ws = wb.add_sheet('Users') row_num = 0 font_style = xlwt.XFStyle() font_style.font.bold = True # 회원정보 중 이름, 단과대, 학과, 학번, 전화번호, 이메일을 내보낸다. columns = ['이름', '단과대', '학과', '학번', '전화번호', '이메일', ] for col_num in range(len(columns)): ws.write(row_num, col_num, columns[col_num], font_style) font_style = xlwt.XFStyle() # 회원 정보를 받아온다. users = ActiveUser.objects.filter(active_year=latest_os.current_year, active_semester=latest_os.current_semester) # 모든 회원의 정보를 반환한다. if category == 1: response['Content-Disposition'] = 'attachment; filename="' + str(latest_os.current_year) + '.' \ + str(latest_os.current_semester) + ' all user list.xls"' for active_user in users: row_num += 1 user = active_user.user row = [user.name, user.get_college_display(), user.get_department_display(), user.student_no, user.phone, user.email] for col_num in range(len(row)): ws.write(row_num, col_num, row[col_num], font_style) # 기존 회원의 정보를 반환한다. elif category == 2: response['Content-Disposition'] = 'attachment; filename="' + str(latest_os.current_year) + '.' \ + str(latest_os.current_semester) + ' old user list.xls"' for active_user in users: if not active_user.is_new: row_num += 1 user = active_user.user row = [user.name, user.get_college_display(), user.get_department_display(), user.student_no, user.phone, user.email] for col_num in range(len(row)): ws.write(row_num, col_num, row[col_num], font_style) # 신입 회원의 정보를 반환한다. elif category == 3: response['Content-Disposition'] = 'attachment; filename="' + str(latest_os.current_year) + '.' \ + str(latest_os.current_semester) + ' new user list.xls"' for active_user in users: if active_user.is_new: row_num += 1 user = active_user.user row = [user.name, user.get_college_display(), user.get_department_display(), user.student_no, user.phone, user.email] for col_num in range(len(row)): ws.write(row_num, col_num, row[col_num], font_style) else: return redirect('core:entrypoint') wb.save(response) return response # 운영진이 아니면 메인 페이지로 간다. else: return redirect('core:entrypoint')
def get_context_data(self, **kwargs): context = super(ActiveUserCreateView, self).get_context_data(**kwargs) context['os'] = OperationScheme.latest() return context