<commit_before># Author: Braedy Kuzma

from django.http import HttpResponse
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.decorators.http import require_POST
from django.views import generic
from .models import Post, Category, Comment, CanSee, Author
from django.db.models import Q
from .forms import PostForm, CommentForm
from .serializers import AuthorSerializer
import base64
import uuid
import itertools
from django.views.generic.edit import CreateView
from rest.authUtils import createBasicAuthToken, parseBasicAuthToken
from rest.models import RemoteCredentials
from rest.serializers import PostSerializer, CommentSerializer
from django.utils.dateparse import parse_datetime
from urllib.parse import urlsplit, urlunsplit
import requests

def postSortKey(postDict):
    return parse_datetime(postDict['published'])

class StreamView(LoginRequiredMixin, generic.ListView):
    login_url = 'login'
    template_name = 'dashboard.html'
    context_object_name = 'latest_post_list'
    def get_queryset(self):
        # Return posts that are visible to everyone (Public, this server only,
        # self posted. Remove unlisted unless you are the creator of post)

        localVisible = Post.objects.filter(
            ((Q(visibility='PUBLIC') | Q(visibility='SERVERONLY'))\
             & Q(unlisted=False)) | Q(author=self.request.user.author)
        )
        #list of all remote creditials we know about.
        #have host, username, password
        #does not contain our own server
        allRemotePosts = []
        hosts = RemoteCredentials.objects.all()
        for host in hosts:
            r = requests.get(host.host+'posts/', data = {'query':'posts'}, auth=(host.username, host.password))
            allRemotePosts += r.json()['posts']

        # Get authors who consider this author a friend
        #friendOf = AuthorFriend.objects \
         #                      .filter(friendId=self.request.user.author.id) \
          #                     .values_list('friend1', flat=True)
        #friends=Author.objects.filter(followee__follower__user__username=self.request.user.username,followee__bidirectional=True)
        # Get posts marked FRIENDS visibility whose authors consider this author
        # a friend

        # friendsPosts = Post.objects\
        #                    .filter(visibility='FRIENDS', author__in=friends,
        #                             unlisted=False)
        #friendsPosts=Post.objects\
         #                   .filter(visibility='FRIENDS')\
          #                  .filter(author__followee__follower__user__username=self.request.user.username,author__followee__bidirectional=True)

        #PURGE THE REMOTE POSTS
        remotePosts=[]
        for remotePost in allRemotePosts:
            if remotePost['unlisted'] == False:
                if remotePost['visibility'] == 'PUBLIC':
                    remotePosts.append(remotePost)
                elif remotePost['visibility'] == 'FRIENDS':
                    #TODO: Do this later, oh my god.
                    pass
                elif remotePost['visibility'] == 'PRIVATE':
                    if self.request.user.author.url in remotePost['visibleTo']:
                        remotePosts.append(remotePost)

        # Get posts you can see
        authorCanSee = CanSee.objects \
                             .filter(visibleTo=self.request.user.author.url) \
                             .values_list('post', flat=True)
        visibleToPosts = Post.objects \
                             .filter(id__in=authorCanSee, visibility="PRIVATE",
                                        unlisted=False)

        #finalQuery = itertools.chain(localVisible, friendsPosts, visibleToPosts)
        finalQuery = itertools.chain(localVisible, visibleToPosts)
        postSerializer = PostSerializer(finalQuery, many=True)
        #postSerializer.data gives us a list of dicts that can be added to the remote posts lists
        posts= postSerializer.data + remotePosts
        posts = sorted(posts, key = postSortKey, reverse=True)

        return posts

    def get_context_data(self, **kwargs):
        context = generic.ListView.get_context_data(self, **kwargs)
        context['postForm'] = PostForm()
        context['commentForm'] = CommentForm()
        return context

@require_POST
@login_required(login_url="login")
def newPost(request):
    # Get form data
    form = PostForm(request.POST)
    if form.is_valid():
        data = form.cleaned_data

        host = 'http://' + request.get_host()
        # Did they upload an image?
        if 'attachImage' in request.FILES:
            # Build a bytes object from all of the image chunks (theoretically
            # only) one, but you never know
            image = request.FILES['attachImage']
            b = bytes()
            for c in image.chunks():
                b += c

            # Encode it in b64
            encoded = base64.b64encode(b)

            # Make the new post
            iPost = Post()
            imageId = uuid.uuid4().hex
            iPost.id = host + '/posts/' + imageId + '/'
            iPost.author = request.user.author

            # These are empty because they're just an extra post
            iPost.title = ''
            iPost.description = ''

            # Set up image content
            iPost.contentType = image.content_type + '; base64'
            iPost.content = encoded

            # Image posts are PRIVATE
            iPost.visibility = 'PRIVATE'

            # Image posts are unlisted
            iPost.unlisted = True

            # Save the image post
            iPost.save()

        # Make new post
        post = Post()

        # Fill in data
        post.id = host + '/posts/' + uuid.uuid4().hex + '/'
        post.author = request.user.author
        post.title = data['title']
        post.contentType = data['contentType']
        post.content = data['content']
        post.visibility = data['visibility']
        post.unlisted = data['unlisted']
        post.description = data['description']

        if 'attachImage' in request.FILES:
            post.content += '\n\n![' + post.title + '](' + host + '/dash/posts/' + imageId + ' "' + post.title + '")'

        # Save the new post
        post.save()

        # Were there any categories?
        if data['categories']:
            # Normalize the categories
            categoryList = data['categories'].split(',')
            categoryList = [i.strip() for i in categoryList]

            # Build Category objects
            for categoryStr in categoryList:
                category = Category()
                category.category = categoryStr
                category.post = post
                category.save()

        if data['visibleTo']:
            visibilityList = data['visibleTo'].split(',')
            visibilityList = [i.strip() for i in visibilityList]

            # Build Category objects
            for author in visibilityList:
                canSee = CanSee()
                canSee.visibleTo = author
                canSee.post = post
                canSee.save()

    # Redirect to the dash
    return redirect('dash:dash')

@require_POST
@login_required(login_url="login")
def newComment(request):
    # Get form data
    data = request.POST

    # Make new comment
    comment = Comment()

    # Fill in data
    comment.author = request.user.author.id
    comment.comment = data['comment']
    comment.contentType = data['contentType']
    comment.post_id = data['post_id']

    hostAddress = urlsplit(data['post_id']).netloc
    userAddress = urlsplit(request.user.author.host).netloc
    if userAddress == hostAddress:
        # Save the new comment
        comment.save()
    else:
        # Post the new comment
        serialized_comment = CommentSerializer(comment).data
        print(hostAddress)
        try:
            host = RemoteCredentials.objects.get(host__contains=hostAddress)
        except RemoteCredentials.DoesNotExist:
            return redirect('dash:dash')
        url = data['post_id'] + 'comments/'
        data = {
            "query": "addComment",
            'post':data['post_id'],
            'comment':serialized_comment
        }
        r = requests.post(url, auth=(host.username, host.password),json=data)

    # Redirect to the dash
    return redirect('dash:dash')

@require_POST
@login_required(login_url="login")
def friendRequest(request):
    # Get form data
    data = request.POST

    #I'm leaving this in until friends are sorted out
    print(data)

    # Redirect to the dash
    return redirect('dash:dash')

class ManagerView(LoginRequiredMixin, generic.ListView):
    login_url = 'login'
    template_name = 'manager.html'
    context_object_name = 'latest_post_list'
    def get_queryset(self):
        # Return posts that are visible to everyone (Public, this server only,
        # self posted)
        localVisible = Post.objects.filter(
            Q(author=self.request.user.author)
        )

        return sorted(localVisible, key=lambda post: post.published, reverse=True)

    def get_context_data(self, **kwargs):
        context = generic.ListView.get_context_data(self, **kwargs)
        context['postForm'] = PostForm()
        context['commentForm'] = CommentForm()
        return context

@login_required(login_url="login")
def post(request, pid):
    pid = 'http://' + request.get_host() + '/posts/' + pid
    post = get_object_or_404(Post, pk=pid)
    if 'base64' in post.contentType:
        return HttpResponse(base64.b64decode(post.content), content_type=post.contentType)
    return render(request, 'post.html', {'post':post})

def author_handler(request, id):
    #Return the foreign author's profile
    if (request.method == 'POST'):
        return HttpResponse(status=405)

    elif (request.method == 'GET'):
        author = Author.objects.get(id=id)
        author.friends = author.friends.all()
        author.url = author.host + 'author/' + str(author.id)
        serializer = AuthorSerializer(author)
        json_data = JSONRenderer().render(serializer.data)

        return HttpResponse(json_data, content_type='application/json')

#class FollowForm(LoginRequiredMixin,CreateView):
 #   ''' Form for sending friend (follow) requests'''
    #model = Follow
    #fields = ['followee']
  #  template_name = 'followform.html'
  #  success_url = '/dash/following'

   # ''' This part of code is for making sure you cant follow yourself and you can't send duplicate follow requests '''
   # def form_valid(self,form):
    #    print(Follow.objects.filter(follower=self.request.user.author,followee=form.instance.followee))
     #   if Follow.objects.filter(follower=self.request.user.author,followee=form.instance.followee).count()>0:
      #      print("Already Followed! Try some other user!")
       #     form.add_error('followee', "Already Followed! Try some other user!")
        #    return self.form_invalid(form)
       # elif form.instance.followee==self.request.user.author:
        #    print("cant follow yourself")
         #   form.add_error('followee', "Can't Follow yourself")
          #  return self.form_invalid(form)
        #else:
         #   print("form valid",Follow.objects.filter(follower=self.request.user.author,followee=form.instance.followee).count())
          #  form.instance.follower = self.request.user.author
           # return super(FollowForm, self).form_valid(form)
class ListFollowsAndFriends(LoginRequiredMixin, generic.ListView):
    ''' Lists whom you are following, who are following you and who are your friends '''

    context_object_name = 'following'
    template_name = 'following.html'

    def get_queryset(self):
        notFriends = Follow.objects.filter(follower=self.request.user.author,bidirectional=False)
        Friends = Follow.objects.filter(follower=self.request.user.author,bidirectional=True)
        FollowingMe = Follow.objects.filter(followee=self.request.user.author,bidirectional=False)
        print(FollowingMe)
        return {'notFriends':notFriends,'Friends':Friends,'FollowingMe':FollowingMe}

@login_required()
def FollowRequests(request):
    ''' Accept or reject Friend requests '''
    friend_requests = Follow.objects.filter(followee=request.user.author,bidirectional=False,reject=False)
    if request.method == 'POST':
        if 'accept' in request.POST:
            follower = request.POST['accept']
            print(follower)
            obj = Follow.objects.get(follower=Author.objects.get(user__username=follower),followee=request.user.author)
            obj.bidirectional=True
            obj.save()
            obj = Follow(followee=Author.objects.get(user__username=follower),follower=request.user.author)
            obj.bidirectional=True
            obj.save()
        elif 'reject' in request.POST:
            follower = request.POST['reject']
            obj = Follow.objects.get(follower=Author.objects.get(user__username=follower),followee=request.user.author)
            obj.reject = True
            obj.save()

    return render(request, 'friendrequests.html', {'followers': friend_requests})
<commit_msg>removed print<commit_after># Author: Braedy Kuzma

from django.http import HttpResponse
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.decorators.http import require_POST
from django.views import generic
from .models import Post, Category, Comment, CanSee, Author
from django.db.models import Q
from .forms import PostForm, CommentForm
from .serializers import AuthorSerializer
import base64
import uuid
import itertools
from django.views.generic.edit import CreateView
from rest.authUtils import createBasicAuthToken, parseBasicAuthToken
from rest.models import RemoteCredentials
from rest.serializers import PostSerializer, CommentSerializer
from django.utils.dateparse import parse_datetime
from urllib.parse import urlsplit, urlunsplit
import requests

def postSortKey(postDict):
    return parse_datetime(postDict['published'])

class StreamView(LoginRequiredMixin, generic.ListView):
    login_url = 'login'
    template_name = 'dashboard.html'
    context_object_name = 'latest_post_list'
    def get_queryset(self):
        # Return posts that are visible to everyone (Public, this server only,
        # self posted. Remove unlisted unless you are the creator of post)

        localVisible = Post.objects.filter(
            ((Q(visibility='PUBLIC') | Q(visibility='SERVERONLY'))\
             & Q(unlisted=False)) | Q(author=self.request.user.author)
        )
        #list of all remote creditials we know about.
        #have host, username, password
        #does not contain our own server
        allRemotePosts = []
        hosts = RemoteCredentials.objects.all()
        for host in hosts:
            r = requests.get(host.host+'posts/', data = {'query':'posts'}, auth=(host.username, host.password))
            allRemotePosts += r.json()['posts']

        # Get authors who consider this author a friend
        #friendOf = AuthorFriend.objects \
         #                      .filter(friendId=self.request.user.author.id) \
          #                     .values_list('friend1', flat=True)
        #friends=Author.objects.filter(followee__follower__user__username=self.request.user.username,followee__bidirectional=True)
        # Get posts marked FRIENDS visibility whose authors consider this author
        # a friend

        # friendsPosts = Post.objects\
        #                    .filter(visibility='FRIENDS', author__in=friends,
        #                             unlisted=False)
        #friendsPosts=Post.objects\
         #                   .filter(visibility='FRIENDS')\
          #                  .filter(author__followee__follower__user__username=self.request.user.username,author__followee__bidirectional=True)

        #PURGE THE REMOTE POSTS
        remotePosts=[]
        for remotePost in allRemotePosts:
            if remotePost['unlisted'] == False:
                if remotePost['visibility'] == 'PUBLIC':
                    remotePosts.append(remotePost)
                elif remotePost['visibility'] == 'FRIENDS':
                    #TODO: Do this later, oh my god.
                    pass
                elif remotePost['visibility'] == 'PRIVATE':
                    if self.request.user.author.url in remotePost['visibleTo']:
                        remotePosts.append(remotePost)

        # Get posts you can see
        authorCanSee = CanSee.objects \
                             .filter(visibleTo=self.request.user.author.url) \
                             .values_list('post', flat=True)
        visibleToPosts = Post.objects \
                             .filter(id__in=authorCanSee, visibility="PRIVATE",
                                        unlisted=False)

        #finalQuery = itertools.chain(localVisible, friendsPosts, visibleToPosts)
        finalQuery = itertools.chain(localVisible, visibleToPosts)
        postSerializer = PostSerializer(finalQuery, many=True)
        #postSerializer.data gives us a list of dicts that can be added to the remote posts lists
        posts= postSerializer.data + remotePosts
        posts = sorted(posts, key = postSortKey, reverse=True)

        return posts

    def get_context_data(self, **kwargs):
        context = generic.ListView.get_context_data(self, **kwargs)
        context['postForm'] = PostForm()
        context['commentForm'] = CommentForm()
        return context

@require_POST
@login_required(login_url="login")
def newPost(request):
    # Get form data
    form = PostForm(request.POST)
    if form.is_valid():
        data = form.cleaned_data

        host = 'http://' + request.get_host()
        # Did they upload an image?
        if 'attachImage' in request.FILES:
            # Build a bytes object from all of the image chunks (theoretically
            # only) one, but you never know
            image = request.FILES['attachImage']
            b = bytes()
            for c in image.chunks():
                b += c

            # Encode it in b64
            encoded = base64.b64encode(b)

            # Make the new post
            iPost = Post()
            imageId = uuid.uuid4().hex
            iPost.id = host + '/posts/' + imageId + '/'
            iPost.author = request.user.author

            # These are empty because they're just an extra post
            iPost.title = ''
            iPost.description = ''

            # Set up image content
            iPost.contentType = image.content_type + '; base64'
            iPost.content = encoded

            # Image posts are PRIVATE
            iPost.visibility = 'PRIVATE'

            # Image posts are unlisted
            iPost.unlisted = True

            # Save the image post
            iPost.save()

        # Make new post
        post = Post()

        # Fill in data
        post.id = host + '/posts/' + uuid.uuid4().hex + '/'
        post.author = request.user.author
        post.title = data['title']
        post.contentType = data['contentType']
        post.content = data['content']
        post.visibility = data['visibility']
        post.unlisted = data['unlisted']
        post.description = data['description']

        if 'attachImage' in request.FILES:
            post.content += '\n\n![' + post.title + '](' + host + '/dash/posts/' + imageId + ' "' + post.title + '")'

        # Save the new post
        post.save()

        # Were there any categories?
        if data['categories']:
            # Normalize the categories
            categoryList = data['categories'].split(',')
            categoryList = [i.strip() for i in categoryList]

            # Build Category objects
            for categoryStr in categoryList:
                category = Category()
                category.category = categoryStr
                category.post = post
                category.save()

        if data['visibleTo']:
            visibilityList = data['visibleTo'].split(',')
            visibilityList = [i.strip() for i in visibilityList]

            # Build Category objects
            for author in visibilityList:
                canSee = CanSee()
                canSee.visibleTo = author
                canSee.post = post
                canSee.save()

    # Redirect to the dash
    return redirect('dash:dash')

@require_POST
@login_required(login_url="login")
def newComment(request):
    # Get form data
    data = request.POST

    # Make new comment
    comment = Comment()

    # Fill in data
    comment.author = request.user.author.id
    comment.comment = data['comment']
    comment.contentType = data['contentType']
    comment.post_id = data['post_id']

    hostAddress = urlsplit(data['post_id']).netloc
    userAddress = urlsplit(request.user.author.host).netloc
    if userAddress == hostAddress:
        # Save the new comment
        comment.save()
    else:
        # Post the new comment
        serialized_comment = CommentSerializer(comment).data
        try:
            host = RemoteCredentials.objects.get(host__contains=hostAddress)
        except RemoteCredentials.DoesNotExist:
            return redirect('dash:dash')
        url = data['post_id'] + 'comments/'
        data = {
            "query": "addComment",
            'post':data['post_id'],
            'comment':serialized_comment
        }
        r = requests.post(url, auth=(host.username, host.password),json=data)

    # Redirect to the dash
    return redirect('dash:dash')

@require_POST
@login_required(login_url="login")
def friendRequest(request):
    # Get form data
    data = request.POST

    #I'm leaving this in until friends are sorted out
    print(data)

    # Redirect to the dash
    return redirect('dash:dash')

class ManagerView(LoginRequiredMixin, generic.ListView):
    login_url = 'login'
    template_name = 'manager.html'
    context_object_name = 'latest_post_list'
    def get_queryset(self):
        # Return posts that are visible to everyone (Public, this server only,
        # self posted)
        localVisible = Post.objects.filter(
            Q(author=self.request.user.author)
        )

        return sorted(localVisible, key=lambda post: post.published, reverse=True)

    def get_context_data(self, **kwargs):
        context = generic.ListView.get_context_data(self, **kwargs)
        context['postForm'] = PostForm()
        context['commentForm'] = CommentForm()
        return context

@login_required(login_url="login")
def post(request, pid):
    pid = 'http://' + request.get_host() + '/posts/' + pid
    post = get_object_or_404(Post, pk=pid)
    if 'base64' in post.contentType:
        return HttpResponse(base64.b64decode(post.content), content_type=post.contentType)
    return render(request, 'post.html', {'post':post})

def author_handler(request, id):
    #Return the foreign author's profile
    if (request.method == 'POST'):
        return HttpResponse(status=405)

    elif (request.method == 'GET'):
        author = Author.objects.get(id=id)
        author.friends = author.friends.all()
        author.url = author.host + 'author/' + str(author.id)
        serializer = AuthorSerializer(author)
        json_data = JSONRenderer().render(serializer.data)

        return HttpResponse(json_data, content_type='application/json')

#class FollowForm(LoginRequiredMixin,CreateView):
 #   ''' Form for sending friend (follow) requests'''
    #model = Follow
    #fields = ['followee']
  #  template_name = 'followform.html'
  #  success_url = '/dash/following'

   # ''' This part of code is for making sure you cant follow yourself and you can't send duplicate follow requests '''
   # def form_valid(self,form):
    #    print(Follow.objects.filter(follower=self.request.user.author,followee=form.instance.followee))
     #   if Follow.objects.filter(follower=self.request.user.author,followee=form.instance.followee).count()>0:
      #      print("Already Followed! Try some other user!")
       #     form.add_error('followee', "Already Followed! Try some other user!")
        #    return self.form_invalid(form)
       # elif form.instance.followee==self.request.user.author:
        #    print("cant follow yourself")
         #   form.add_error('followee', "Can't Follow yourself")
          #  return self.form_invalid(form)
        #else:
         #   print("form valid",Follow.objects.filter(follower=self.request.user.author,followee=form.instance.followee).count())
          #  form.instance.follower = self.request.user.author
           # return super(FollowForm, self).form_valid(form)
class ListFollowsAndFriends(LoginRequiredMixin, generic.ListView):
    ''' Lists whom you are following, who are following you and who are your friends '''

    context_object_name = 'following'
    template_name = 'following.html'

    def get_queryset(self):
        notFriends = Follow.objects.filter(follower=self.request.user.author,bidirectional=False)
        Friends = Follow.objects.filter(follower=self.request.user.author,bidirectional=True)
        FollowingMe = Follow.objects.filter(followee=self.request.user.author,bidirectional=False)
        print(FollowingMe)
        return {'notFriends':notFriends,'Friends':Friends,'FollowingMe':FollowingMe}

@login_required()
def FollowRequests(request):
    ''' Accept or reject Friend requests '''
    friend_requests = Follow.objects.filter(followee=request.user.author,bidirectional=False,reject=False)
    if request.method == 'POST':
        if 'accept' in request.POST:
            follower = request.POST['accept']
            print(follower)
            obj = Follow.objects.get(follower=Author.objects.get(user__username=follower),followee=request.user.author)
            obj.bidirectional=True
            obj.save()
            obj = Follow(followee=Author.objects.get(user__username=follower),follower=request.user.author)
            obj.bidirectional=True
            obj.save()
        elif 'reject' in request.POST:
            follower = request.POST['reject']
            obj = Follow.objects.get(follower=Author.objects.get(user__username=follower),followee=request.user.author)
            obj.reject = True
            obj.save()

    return render(request, 'friendrequests.html', {'followers': friend_requests})
<|endoftext|>


<commit_before>##############################################################################
# Copyright (c) 2013-2018, Lawrence Livermore National Security, LLC.
# Produced at the Lawrence Livermore National Laboratory.
#
# This file is part of Spack.
# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
# LLNL-CODE-647188
#
# For details, see https://github.com/spack/spack
# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License (as
# published by the Free Software Foundation) version 2.1, February 1999.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
# conditions of the GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##############################################################################
from spack import *

class Log4cplus(CMakePackage):
    """log4cplus is a simple to use C++ logging API
    providing thread-safe, flexible, and arbitrarily
    granular control over log management and configuration."""

    homepage = "https://sourceforge.net/projects/log4cplus/"
    url      = "https://nchc.dl.sourceforge.net/project/log4cplus/log4cplus-stable/1.2.0/log4cplus-1.2.0.tar.gz"

    version('1.2.0', 'e250f0f431c0723f8b625323e7b6465d')
<commit_msg>Add new versions for log4cplus. (#8621)<commit_after>##############################################################################
# Copyright (c) 2013-2018, Lawrence Livermore National Security, LLC.
# Produced at the Lawrence Livermore National Laboratory.
#
# This file is part of Spack.
# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
# LLNL-CODE-647188
#
# For details, see https://github.com/spack/spack
# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License (as
# published by the Free Software Foundation) version 2.1, February 1999.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
# conditions of the GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##############################################################################
from spack import *

class Log4cplus(CMakePackage):
    """log4cplus is a simple to use C++ logging API
    providing thread-safe, flexible, and arbitrarily
    granular control over log management and configuration."""

    homepage = "https://sourceforge.net/projects/log4cplus/"
    url      = "https://download.sourceforge.net/project/log4cplus/log4cplus-stable/2.0.1/log4cplus-2.0.1.tar.bz2"

    version('2.0.1', 'ec01c03241ebd31127a44d1880830d8f')
    version('1.2.1', 'e4e6c38b065b70b5d6efc238a5106bc9')
    version('1.2.0', 'e250f0f431c0723f8b625323e7b6465d')
<|endoftext|>


<commit_before>##############################################################################
# Copyright (c) 2013-2016, Lawrence Livermore National Security, LLC.
# Produced at the Lawrence Livermore National Laboratory.
#
# This file is part of Spack.
# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
# LLNL-CODE-647188
#
# For details, see https://github.com/llnl/spack
# Please also see the LICENSE file for our notice and the LGPL.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License (as
# published by the Free Software Foundation) version 2.1, February 1999.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
# conditions of the GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##############################################################################
from spack import *
import sys

class PyPillow(PythonPackage):
    """Pillow is a fork of the Python Imaging Library (PIL). It adds image
    processing capabilities to your Python interpreter. This library supports
    many file formats, and provides powerful image processing and graphics
    capabilities."""

    homepage = "https://python-pillow.org/"
    url = "https://pypi.python.org/packages/source/P/Pillow/Pillow-3.0.0.tar.gz"

    # TODO: This version should be deleted once the next release comes out.
    # TODO: It fixes a bug that prevented us from linking to Tk/Tcl.
    # TODO: Tk/Tcl support is necessary for tkinter bitmap and photo images.
    # TODO: If you require this support, run the following command:
    # TODO:     `spack install py-pillow@3.3.0.dev0 ^python+tk`
    version('3.3.0.dev0', git='https://github.com/python-pillow/Pillow.git',
            commit='30eced62868141a6c859a4370efd40b9434a7c3f')

    version('3.2.0', '7cfd093c11205d9e2ebe3c51dfcad510', preferred=True)
    version('3.0.0', 'fc8ac44e93da09678eac7e30c9b7377d')

    provides('pil')

    # These defaults correspond to Pillow defaults
    variant('jpeg', default=True, description='Provide JPEG functionality')
    variant('zlib', default=True, description='Access to compressed PNGs')
    variant('tiff', default=False, description='Access to TIFF files')
    variant('freetype', default=False, description='Font related services')
    variant('lcms', default=False, description='Color management')
    variant('jpeg2000', default=False,
            description='Provide JPEG 2000 functionality')

    # Spack does not (yet) support these modes of building
    # variant('webp', default=False, description='Provide the WebP format')
    # variant('webpmux', default=False,
    #         description='WebP metadata, relies on WebP support')
    # variant('imagequant', default=False,
    #         description='Provide improved color quantization')

    # Required dependencies
    depends_on('binutils', type='build', when=sys.platform != 'darwin')
    depends_on('py-setuptools', type='build')

    # Recommended dependencies
    depends_on('jpeg', when='+jpeg')
    depends_on('zlib', when='+zlib')

    # Optional dependencies
    depends_on('libtiff', when='+tiff')
    depends_on('freetype', when='+freetype')
    depends_on('lcms', when='+lcms')
    depends_on('openjpeg', when='+jpeg2000')

    # Spack does not (yet) support these modes of building
    # depends_on('webp', when='+webp')
    # depends_on('webpmux', when='+webpmux')
    # depends_on('imagequant', when='+imagequant')

    phases = ['build_ext', 'install']

    def patch(self):
        """Patch setup.py to provide lib and include directories
        for dependencies."""

        spec = self.spec
        setup = FileFilter('setup.py')

        if '+jpeg' in spec:
            setup.filter('JPEG_ROOT = None',
                         'JPEG_ROOT = ("{0}", "{1}")'.format(
                             spec['jpeg'].prefix.lib,
                             spec['jpeg'].prefix.include))
        if '+zlib' in spec:
            setup.filter('ZLIB_ROOT = None',
                         'ZLIB_ROOT = ("{0}", "{1}")'.format(
                             spec['zlib'].prefix.lib,
                             spec['zlib'].prefix.include))
        if '+tiff' in spec:
            setup.filter('TIFF_ROOT = None',
                         'TIFF_ROOT = ("{0}", "{1}")'.format(
                             spec['libtiff'].prefix.lib,
                             spec['libtiff'].prefix.include))
        if '+freetype' in spec:
            setup.filter('FREETYPE_ROOT = None',
                         'FREETYPE_ROOT = ("{0}", "{1}")'.format(
                             spec['freetype'].prefix.lib,
                             spec['freetype'].prefix.include))
        if '+lcms' in spec:
            setup.filter('LCMS_ROOT = None',
                         'LCMS_ROOT = ("{0}", "{1}")'.format(
                             spec['lcms'].prefix.lib,
                             spec['lcms'].prefix.include))
        if '+jpeg2000' in spec:
            setup.filter('JPEG2K_ROOT = None',
                         'JPEG2K_ROOT = ("{0}", "{1}")'.format(
                             spec['openjpeg'].prefix.lib,
                             spec['openjpeg'].prefix.include))

    def build_ext_args(self, spec, prefix):
        def variant_to_flag(variant):
            able = 'enable' if '+{0}'.format(variant) in spec else 'disable'
            return '--{0}-{1}'.format(able, variant)

        variants = ['jpeg', 'zlib', 'tiff', 'freetype', 'lcms', 'jpeg2000']
        return list(map(variant_to_flag, variants))
<commit_msg>py-pillow: ensure that RPATH includes graphics libraries (#4522)<commit_after>##############################################################################
# Copyright (c) 2013-2016, Lawrence Livermore National Security, LLC.
# Produced at the Lawrence Livermore National Laboratory.
#
# This file is part of Spack.
# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
# LLNL-CODE-647188
#
# For details, see https://github.com/llnl/spack
# Please also see the LICENSE file for our notice and the LGPL.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License (as
# published by the Free Software Foundation) version 2.1, February 1999.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
# conditions of the GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##############################################################################
from spack import *
import sys

class PyPillow(PythonPackage):
    """Pillow is a fork of the Python Imaging Library (PIL). It adds image
    processing capabilities to your Python interpreter. This library supports
    many file formats, and provides powerful image processing and graphics
    capabilities."""

    homepage = "https://python-pillow.org/"
    url = "https://pypi.python.org/packages/source/P/Pillow/Pillow-3.0.0.tar.gz"

    # TODO: This version should be deleted once the next release comes out.
    # TODO: It fixes a bug that prevented us from linking to Tk/Tcl.
    # TODO: Tk/Tcl support is necessary for tkinter bitmap and photo images.
    # TODO: If you require this support, run the following command:
    # TODO:     `spack install py-pillow@3.3.0.dev0 ^python+tk`
    version('3.3.0.dev0', git='https://github.com/python-pillow/Pillow.git',
            commit='30eced62868141a6c859a4370efd40b9434a7c3f')

    version('3.2.0', '7cfd093c11205d9e2ebe3c51dfcad510', preferred=True)
    version('3.0.0', 'fc8ac44e93da09678eac7e30c9b7377d')

    provides('pil')

    # These defaults correspond to Pillow defaults
    variant('jpeg', default=True, description='Provide JPEG functionality')
    variant('zlib', default=True, description='Access to compressed PNGs')
    variant('tiff', default=False, description='Access to TIFF files')
    variant('freetype', default=False, description='Font related services')
    variant('lcms', default=False, description='Color management')
    variant('jpeg2000', default=False,
            description='Provide JPEG 2000 functionality')

    # Spack does not (yet) support these modes of building
    # variant('webp', default=False, description='Provide the WebP format')
    # variant('webpmux', default=False,
    #         description='WebP metadata, relies on WebP support')
    # variant('imagequant', default=False,
    #         description='Provide improved color quantization')

    # Required dependencies
    depends_on('binutils', type='build', when=sys.platform != 'darwin')
    depends_on('py-setuptools', type='build')

    # Recommended dependencies
    depends_on('jpeg', when='+jpeg')
    depends_on('zlib', when='+zlib')

    # Optional dependencies
    depends_on('libtiff', when='+tiff')
    depends_on('freetype', when='+freetype')
    depends_on('lcms', when='+lcms')
    depends_on('openjpeg', when='+jpeg2000')

    # Spack does not (yet) support these modes of building
    # depends_on('webp', when='+webp')
    # depends_on('webpmux', when='+webpmux')
    # depends_on('imagequant', when='+imagequant')

    phases = ['build_ext', 'install']

    def patch(self):
        """Patch setup.py to provide lib and include directories
        for dependencies."""

        spec = self.spec
        setup = FileFilter('setup.py')

        if '+jpeg' in spec:
            setup.filter('JPEG_ROOT = None',
                         'JPEG_ROOT = ("{0}", "{1}")'.format(
                             spec['jpeg'].prefix.lib,
                             spec['jpeg'].prefix.include))
        if '+zlib' in spec:
            setup.filter('ZLIB_ROOT = None',
                         'ZLIB_ROOT = ("{0}", "{1}")'.format(
                             spec['zlib'].prefix.lib,
                             spec['zlib'].prefix.include))
        if '+tiff' in spec:
            setup.filter('TIFF_ROOT = None',
                         'TIFF_ROOT = ("{0}", "{1}")'.format(
                             spec['libtiff'].prefix.lib,
                             spec['libtiff'].prefix.include))
        if '+freetype' in spec:
            setup.filter('FREETYPE_ROOT = None',
                         'FREETYPE_ROOT = ("{0}", "{1}")'.format(
                             spec['freetype'].prefix.lib,
                             spec['freetype'].prefix.include))
        if '+lcms' in spec:
            setup.filter('LCMS_ROOT = None',
                         'LCMS_ROOT = ("{0}", "{1}")'.format(
                             spec['lcms'].prefix.lib,
                             spec['lcms'].prefix.include))
        if '+jpeg2000' in spec:
            setup.filter('JPEG2K_ROOT = None',
                         'JPEG2K_ROOT = ("{0}", "{1}")'.format(
                             spec['openjpeg'].prefix.lib,
                             spec['openjpeg'].prefix.include))

    def build_ext_args(self, spec, prefix):
        def variant_to_flag(variant):
            able = 'enable' if '+{0}'.format(variant) in spec else 'disable'
            return '--{0}-{1}'.format(able, variant)

        variants = ['jpeg', 'zlib', 'tiff', 'freetype', 'lcms', 'jpeg2000']
        args = list(map(variant_to_flag, variants))
        args.extend(['--rpath=%s' % ":".join(self.rpath)])
        return args
<|endoftext|>


<commit_before>import logging
import jsonpickle
from datetime import datetime

from sqlalchemy import asc, desc, UniqueConstraint, CheckConstraint

from ..extensions import db
from .services import create_add_transaction_from_order
from labsys.auth.models import User

ADD = 1
SUB = 2

logging.basicConfig(level=logging.INFO)

class Base(db.Model):
    __abstract__ = True
    id = db.Column(db.Integer, primary_key=True)

    def create(self):
        db.session.add(self)
        db.session.commit()
        return self

    def delete(self):
        db.session.delete(self)
        db.session.commit()
        return self

    # TODO: make query object
    """
    def query(self, obj):
        for each attribute in self and obj
        if attribute in obj is not null
            compare with attribute
    """
    def toJSON(self):
        return jsonpickle.encode(self)

class TimeStampedModelMixin(db.Model):
    __abstract__ = True
    created_on = db.Column(db.DateTime, default=datetime.utcnow)
    updated_on = db.Column(
        db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)

class Product(Base):
    __tablename__ = 'products'

    def __init__(self, name, specification, **kwargs):
        super().__init__(**kwargs)
        self.name = name
        self.specifications.append(specification)

    def __str__(self):
        return self.name

    # Columns
    name = db.Column(db.String(128), nullable=False)
    stock_minimum = db.Column(db.Integer, default=1, nullable=False)
    # Relationships
    specifications = db.relationship(
        'Specification', backref='product')

    def get_base_spec(self):
        if len(self.specifications) > 0:
            return self.specifications[0]
        return None

class Specification(Base):

    def __init__(self, catalog_number, manufacturer, units=1,
                 **kwargs):
        super().__init__(**kwargs)
        self.catalog_number = catalog_number
        self.manufacturer = manufacturer
        self.units = units

    __tablename__ = 'specifications'
    __table_args__ = (UniqueConstraint(
        'manufacturer', 'catalog_number', name='manufacturer_catalog'), )
    # Columns
    product_id = db.Column(
        db.Integer, db.ForeignKey('products.id'), nullable=False)
    manufacturer = db.Column(db.String(128), nullable=False)
    catalog_number = db.Column(db.String(128), nullable=False)
    units = db.Column(db.Integer, default=1, nullable=False)

class Stock(Base):
    __tablename__ = 'stocks'
    # Columns
    name = db.Column(db.String(128), nullable=False)
    # Relationships
    stock_products = db.relationship('StockProduct', backref='stock')

    def get_in_stock(self, product, lot_number):
        for stock_product in self.stock_products:
            if stock_product.product == product \
                    and stock_product.lot_number == lot_number:
                return stock_product
        return None

    def has_enough(self, product, lot_number, amount):
        if amount < 1:
            raise ValueError('Amount must be greater than 0')
        in_stock = self.get_in_stock(product, lot_number)
        if in_stock is None or in_stock.amount < amount:
            return False
        return True

    def total(self, product):
        total = 0
        for sp in self.stock_products:
            if sp.product_id == product.id:
                total += sp.amount
        return total

    def add(self, product, lot_number, expiration_date, amount):
        """
        amount: total units to be added
        """
        if amount < 1 or isinstance(amount, int) is False:
            raise ValueError('Amount must be a positive integer')
        stock_product = self.get_in_stock(product, lot_number)
        if stock_product is None:
            stock_product = StockProduct(
                self, product, lot_number, expiration_date)
        else:
            if expiration_date != stock_product.expiration_date:
                logging.warning('Different expiration date, updating...')
        stock_product.expiration_date = expiration_date
        stock_product.amount += amount
        db.session.add(stock_product)

    def subtract(self, product, lot_number, amount):
        """
        amount: total units to be subtracted
        """
        if amount < 1 or isinstance(amount, int) is False:
            raise ValueError('Amount must be a positive integer')
        in_stock = self.get_in_stock(product, lot_number)
        if in_stock is None:
            raise ValueError('There is no {} in stock'.format(product.name))
        if self.has_enough(product, lot_number, amount):
            in_stock.amount -= amount
            return True
        raise ValueError('Not enough in stock')

    @staticmethod
    def get_reactive_stock():
        return Stock.query.first()

    @staticmethod
    def insert_stock(name):
        stock = Stock.query.filter_by(name=name).first()
        if stock is None:
            stock = Stock(name=name)
        db.session.add(stock)
        db.session.commit()

class StockProduct(Base):
    __tablename__ = 'stock_products'
    __table_args__ = (UniqueConstraint(
        'product_id', 'stock_id', 'lot_number', name='stock_product'), )

    def __init__(self, stock, product, lot_number, expiration_date,
                 amount=0, **kwargs):
        super().__init__(**kwargs)
        self.stock = stock
        self.product = product
        self.lot_number = lot_number
        self.expiration_date = expiration_date
        self.amount = amount if amount > 0 else 0

    def __str__(self):
        return '(Stock: {}, Product: {}, Lot: {}, Exp.: {}, Amount: {})'\
            .format(
                self.stock.name,
                self.product.name,
                self.lot_number,
                self.expiration_date,
                self.amount,
            )

    # Columns
    stock_id = db.Column(
        db.Integer, db.ForeignKey('stocks.id'), nullable=False)
    product_id = db.Column(
        db.Integer, db.ForeignKey('products.id'), nullable=False)
    lot_number = db.Column(db.String(64), nullable=False)
    expiration_date = db.Column(db.Date, nullable=True)
    amount = db.Column(db.Integer, default=0, nullable=False)
    # Relationships
    product = db.relationship('Product', backref=db.backref('stock_products', lazy=True))

class OrderItem(Base):
    __tablename__ = 'order_items'
    __tableargs__ = (UniqueConstraint(
        'item_id', 'order_id', name='order_item'), )
    # Columns
    item_id = db.Column(
        db.Integer, db.ForeignKey('specifications.id'), nullable=False)
    order_id = db.Column(
        db.Integer, db.ForeignKey('orders.id'), nullable=False)
    amount = db.Column(db.Integer, default=1, nullable=False)
    lot_number = db.Column(db.String(64), nullable=False)
    expiration_date = db.Column(
        db.Date, default=datetime.utcnow().date, nullable=True)
    added_to_stock = db.Column(db.Boolean, default=False, nullable=True)
    # Relationships
    item = db.relationship(Specification)

class Order(Base, TimeStampedModelMixin):
    __tablename__ = 'orders'
    # Columns
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
    invoice = db.Column(db.String(128), nullable=True)
    invoice_type = db.Column(db.String(128), nullable=True)
    financier = db.Column(db.String(128), nullable=True)
    notes = db.Column(db.String(256), nullable=True)
    order_date = db.Column(
        db.DateTime, default=datetime.utcnow, nullable=False)
    # Relationships
    items = db.relationship(
        OrderItem, backref='order', cascade='all, delete-orphan')
    # lazy=True: accessing orders will load them from db (user.orders)
    user = db.relationship(
        User, backref=db.backref('orders', lazy=True))

    @property
    def is_executed(self):
        for order_item in self.items:
            if not order_item.added_to_stock:
                return False
        return True

    def get_pending_items(self):
        return [item for item in self.items if not item.added_to_stock]

class Transaction(Base, TimeStampedModelMixin):
    __tablename__ = 'transactions'
    # Columns
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
    product_id = db.Column(
        db.Integer, db.ForeignKey('products.id'), nullable=False)
    stock_id = db.Column(
        db.Integer, db.ForeignKey('stocks.id'), nullable=False)
    amount = db.Column(db.Integer, nullable=False)
    category = db.Column(db.Integer, nullable=False)
    # TODO: make sure alembic migrations recognizes this
    __table_args__ = (
        CheckConstraint(amount > 0, name='amount_is_positive'), {})

    # Relationships
    user = db.relationship(
        User, backref=db.backref('transactions', lazy=True))
    product = db.relationship(
        Product, backref=db.backref('transactions', lazy=True))
    stock = db.relationship(
        Stock, backref=db.backref('transactions', lazy=True))

    def __init__(self, user, product, lot_number, amount, stock, category,
                 expiration_date=None):
        self.user = user
        self.product = product
        self.amount = amount
        self.stock = stock
        self.category = category
<commit_msg>:shirt: Corrige linting<commit_after>import logging
import jsonpickle
from datetime import datetime

from sqlalchemy import UniqueConstraint, CheckConstraint

from labsys.extensions import db
from labsys.auth.models import User

ADD = 1
SUB = 2

logging.basicConfig(level=logging.INFO)

class Base(db.Model):
    __abstract__ = True
    id = db.Column(db.Integer, primary_key=True)

    def create(self):
        db.session.add(self)
        db.session.commit()
        return self

    def delete(self):
        db.session.delete(self)
        db.session.commit()
        return self

    # TODO: make query object
    """
    def query(self, obj):
        for each attribute in self and obj
        if attribute in obj is not null
            compare with attribute
    """

    def toJSON(self):
        return jsonpickle.encode(self)

class TimeStampedModelMixin(db.Model):
    __abstract__ = True
    created_on = db.Column(db.DateTime, default=datetime.utcnow)
    updated_on = db.Column(
        db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)

class Product(Base):
    __tablename__ = 'products'

    def __init__(self, name, specification, **kwargs):
        super().__init__(**kwargs)
        self.name = name
        self.specifications.append(specification)

    def __str__(self):
        return self.name

    # Columns
    name = db.Column(db.String(128), nullable=False)
    stock_minimum = db.Column(db.Integer, default=1, nullable=False)
    # Relationships
    specifications = db.relationship(
        'Specification', backref='product')

    def get_base_spec(self):
        if len(self.specifications) > 0:
            return self.specifications[0]
        return None

class Specification(Base):

    def __init__(self, catalog_number, manufacturer, units=1,
                 **kwargs):
        super().__init__(**kwargs)
        self.catalog_number = catalog_number
        self.manufacturer = manufacturer
        self.units = units

    __tablename__ = 'specifications'
    __table_args__ = (UniqueConstraint(
        'manufacturer', 'catalog_number', name='manufacturer_catalog'), )
    # Columns
    product_id = db.Column(
        db.Integer, db.ForeignKey('products.id'), nullable=False)
    manufacturer = db.Column(db.String(128), nullable=False)
    catalog_number = db.Column(db.String(128), nullable=False)
    units = db.Column(db.Integer, default=1, nullable=False)

class Stock(Base):
    __tablename__ = 'stocks'
    # Columns
    name = db.Column(db.String(128), nullable=False)
    # Relationships
    stock_products = db.relationship('StockProduct', backref='stock')

    def get_in_stock(self, product, lot_number):
        for stock_product in self.stock_products:
            if stock_product.product == product \
                    and stock_product.lot_number == lot_number:
                return stock_product
        return None

    def has_enough(self, product, lot_number, amount):
        if amount < 1:
            raise ValueError('Amount must be greater than 0')
        in_stock = self.get_in_stock(product, lot_number)
        if in_stock is None or in_stock.amount < amount:
            return False
        return True

    def total(self, product):
        total = 0
        for sp in self.stock_products:
            if sp.product_id == product.id:
                total += sp.amount
        return total

    def add(self, product, lot_number, expiration_date, amount):
        """
        amount: total units to be added
        """
        if amount < 1 or isinstance(amount, int) is False:
            raise ValueError('Amount must be a positive integer')
        stock_product = self.get_in_stock(product, lot_number)
        if stock_product is None:
            stock_product = StockProduct(
                self, product, lot_number, expiration_date)
        else:
            if expiration_date != stock_product.expiration_date:
                logging.warning('Different expiration date, updating...')
        stock_product.expiration_date = expiration_date
        stock_product.amount += amount
        db.session.add(stock_product)

    def subtract(self, product, lot_number, amount):
        """
        amount: total units to be subtracted
        """
        if amount < 1 or isinstance(amount, int) is False:
            raise ValueError('Amount must be a positive integer')
        in_stock = self.get_in_stock(product, lot_number)
        if in_stock is None:
            raise ValueError('There is no {} in stock'.format(product.name))
        if self.has_enough(product, lot_number, amount):
            in_stock.amount -= amount
            return True
        raise ValueError('Not enough in stock')

    @staticmethod
    def get_reactive_stock():
        return Stock.query.first()

    @staticmethod
    def insert_stock(name):
        stock = Stock.query.filter_by(name=name).first()
        if stock is None:
            stock = Stock(name=name)
        db.session.add(stock)
        db.session.commit()

class StockProduct(Base):
    __tablename__ = 'stock_products'
    __table_args__ = (UniqueConstraint(
        'product_id', 'stock_id', 'lot_number', name='stock_product'), )

    def __init__(self, stock, product, lot_number, expiration_date,
                 amount=0, **kwargs):
        super().__init__(**kwargs)
        self.stock = stock
        self.product = product
        self.lot_number = lot_number
        self.expiration_date = expiration_date
        self.amount = amount if amount > 0 else 0

    def __str__(self):
        return '(Stock: {}, Product: {}, Lot: {}, Exp.: {}, Amount: {})'\
            .format(
                self.stock.name,
                self.product.name,
                self.lot_number,
                self.expiration_date,
                self.amount,
            )

    # Columns
    stock_id = db.Column(
        db.Integer, db.ForeignKey('stocks.id'), nullable=False)
    product_id = db.Column(
        db.Integer, db.ForeignKey('products.id'), nullable=False)
    lot_number = db.Column(db.String(64), nullable=False)
    expiration_date = db.Column(db.Date, nullable=True)
    amount = db.Column(db.Integer, default=0, nullable=False)
    # Relationships
    product = db.relationship(
        'Product', backref=db.backref('stock_products', lazy=True))

class OrderItem(Base):
    __tablename__ = 'order_items'
    __tableargs__ = (UniqueConstraint(
        'item_id', 'order_id', name='order_item'), )
    # Columns
    item_id = db.Column(
        db.Integer, db.ForeignKey('specifications.id'), nullable=False)
    order_id = db.Column(
        db.Integer, db.ForeignKey('orders.id'), nullable=False)
    amount = db.Column(db.Integer, default=1, nullable=False)
    lot_number = db.Column(db.String(64), nullable=False)
    expiration_date = db.Column(
        db.Date, default=datetime.utcnow().date, nullable=True)
    added_to_stock = db.Column(db.Boolean, default=False, nullable=True)
    # Relationships
    item = db.relationship(Specification)

class Order(Base, TimeStampedModelMixin):
    __tablename__ = 'orders'
    # Columns
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
    invoice = db.Column(db.String(128), nullable=True)
    invoice_type = db.Column(db.String(128), nullable=True)
    financier = db.Column(db.String(128), nullable=True)
    notes = db.Column(db.String(256), nullable=True)
    order_date = db.Column(
        db.DateTime, default=datetime.utcnow, nullable=False)
    # Relationships
    items = db.relationship(
        OrderItem, backref='order', cascade='all, delete-orphan')
    # lazy=True: accessing orders will load them from db (user.orders)
    user = db.relationship(
        User, backref=db.backref('orders', lazy=True))

    @property
    def is_executed(self):
        for order_item in self.items:
            if not order_item.added_to_stock:
                return False
        return True

    def get_pending_items(self):
        return [item for item in self.items if not item.added_to_stock]

class Transaction(Base, TimeStampedModelMixin):
    __tablename__ = 'transactions'
    # Columns
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
    product_id = db.Column(
        db.Integer, db.ForeignKey('products.id'), nullable=False)
    stock_id = db.Column(
        db.Integer, db.ForeignKey('stocks.id'), nullable=False)
    amount = db.Column(db.Integer, nullable=False)
    category = db.Column(db.Integer, nullable=False)
    # TODO: make sure alembic migrations recognizes this
    __table_args__ = (
        CheckConstraint(amount > 0, name='amount_is_positive'), {})

    # Relationships
    user = db.relationship(
        User, backref=db.backref('transactions', lazy=True))
    product = db.relationship(
        Product, backref=db.backref('transactions', lazy=True))
    stock = db.relationship(
        Stock, backref=db.backref('transactions', lazy=True))

    def __init__(self, user, product, lot_number, amount, stock, category,
                 expiration_date=None):
        self.user = user
        self.product = product
        self.amount = amount
        self.stock = stock
        self.category = category
<|endoftext|>


<commit_before>#!/usr/bin/env python2

import os
import sys
from xml.dom.minidom import getDOMImplementation

elements = [None, "H", "He", "Li", "Be", "B", "C", "N", "O", "F", "Ne", "Na",
            "Mg", "Al", "Si", "P", "S", "Cl", "Ar", "K", "Ca", "Sc", "Ti", "V",
            "Cr", "Mn", "Fe", "Co", "Ni", "Cu", "Zn", "Ga", "Ge", "As", "Se",
            "Br", "Kr", "Rb", "Sr", "Y", "Zr", "Nb", "Mo", "Tc", "Ru", "Rh",
            "Pd", "Ag", "Cd", "In", "Sn", "Sb", "Te", "I", "Xe", "Cs", "Ba",
            "La", "Ce", "Pr", "Nd", "Pm", "Sm", "Eu", "Gd", "Tb", "Dy", "Ho",
            "Er", "Tm", "Yb", "Lu", "Hf", "Ta", "W", "Re", "Os", "Ir", "Pt",
            "Au", "Hg", "Tl", "Pb", "Bi", "Po", "At", "Rn", "Fr", "Ra", "Ac",
            "Th", "Pa", "U", "Np", "Pu", "Am", "Cm", "Bk", "Cf", "Es", "Fm",
            "Md", "No", "Lr", "Rf", "Db", "Sg", "Bh", "Hs", "Mt", "Ds", "Rg",
            "Cn"]

class Xsdir(object):

    def __init__(self, filename):
        self.f = open(filename, 'r')
        self.filename = os.path.abspath(filename)
        self.directory = os.path.dirname(filename)
        self.awr = {}
        self.tables = []

        self.filetype = set()
        self.recordlength = set()
        self.entries = set()

        # Read first section (DATAPATH)
        line = self.f.readline()
        words = line.split()
        if words:
            if words[0].lower().startswith('datapath'):
                index = line.index('=')
                self.datapath = line[index+1:].strip()
            else:
                self.f.seek(0)

        # Read second section
        line = self.f.readline()
        words = line.split()
        assert len(words) == 3
        assert words[0].lower() == 'atomic'
        assert words[1].lower() == 'weight'
        assert words[2].lower() == 'ratios'

        while True:
            line = self.f.readline()
            words = line.split()

            # Check for end of second section
            if len(words) % 2 != 0 or words[0] == 'directory':
                break

            for zaid, awr in zip(words[::2], words[1::2]):
                self.awr[zaid] = awr

        # Read third section
        while words[0] != 'directory':
            words = self.f.readline().split()

        while True:
            words = self.f.readline().split()
            if not words:
                break

            # Handle continuation lines
            while words[-1] == '+':
                extraWords = self.f.readline().split()
                words = words + extraWords
            assert len(words) >= 7

            # Create XsdirTable object and add to line
            table = XsdirTable(self.directory)
            self.tables.append(table)

            # All tables have at least 7 attributes
            table.name = words[0]
            table.awr = float(words[1])
            table.filename = words[2]
            table.access = words[3]
            table.filetype = int(words[4])
            table.location = int(words[5])
            table.length = int(words[6])

            self.filetype.add(table.filetype)

            if len(words) > 7:
                table.recordlength = int(words[7])
                self.recordlength.add(table.recordlength)
            if len(words) > 8:
                table.entries = int(words[8])
                self.entries.add(table.entries)
            if len(words) > 9:
                table.temperature = float(words[9])
            if len(words) > 10:
                table.ptable = (words[10] == 'ptable')

        if len(self.filetype) == 1:
            if 1 in self.filetype:
                self.filetype = 'ascii'
            elif 2 in self.filetype:
                self.filetype = 'binary'
        else:
            self.filetype = None

        if len(self.recordlength) == 1:
            self.recordlength = list(self.recordlength)[0]
        else:
            self.recordlength = None
        if len(self.entries) == 1:
            self.entries = list(self.entries)[0]
        else:
            self.recordlength = None

    def to_xml(self):
        # Create XML document
        impl = getDOMImplementation()
        doc = impl.createDocument(None, "cross_sections", None)

        # Get root element
        root = doc.documentElement

        # Add a directory node
        if self.directory:
            directoryNode = doc.createElement("directory")
            text = doc.createTextNode(self.directory)
            directoryNode.appendChild(text)
            root.appendChild(directoryNode)

            for table in self.tables:
                table.path = os.path.basename(table.path)

        # Add filetype, record_length and entries nodes
        if self.filetype:
            node = doc.createElement("filetype")
            text = doc.createTextNode(self.filetype)
            node.appendChild(text)
            root.appendChild(node)
        if self.recordlength:
            node = doc.createElement("record_length")
            text = doc.createTextNode(str(self.recordlength))
            node.appendChild(text)
            root.appendChild(node)
        if self.entries:
            node = doc.createElement("entries")
            text = doc.createTextNode(str(self.entries))
            node.appendChild(text)
            root.appendChild(node)

        # Add a node for each table
        for table in self.tables:
            if table.name[-1] in ['e', 'p', 'u', 'h', 'g', 'm', 'd']:
                continue
            node = table.to_xml_node(doc)
            root.appendChild(node)

        return doc

class XsdirTable(object):

    def __init__(self, directory=None):
        self.directory = None
        self.name = None
        self.awr = None
        self.filename = None
        self.access = None
        self.filetype = None
        self.location = None
        self.length = None
        self.recordlength = None
        self.entries = None
        self.temperature = None
        self.ptable = False

    @property
    def path(self):
        if self.directory:
            return os.path.join(self.directory, self.filename)
        else:
            return self.filename

    @path.setter
    def path(self, value):
        self.diretory = ''
        self.filename = value

    @property
    def metastable(self):
        # Only valid for neutron cross-sections
        if not self.name.endswith('c'):
            return

        # Handle special case of Am-242 and Am-242m
        if self.zaid == '95242':
            return 1
        elif self.zaid == '95642':
            return 0

        # All other cases
        A = int(self.zaid) % 1000
        if A > 300:
            return 1
        else:
            return 0

    @property
    def alias(self):
        zaid = self.zaid
        if zaid:
            Z = int(zaid[:-3])
            A = zaid[-3:]

            if A == '000':
                s = 'Nat'
            elif zaid == '95242':
                s = '242m'
            elif zaid == '95642':
                s = '242'
            elif int(A) > 300:
                s = str(int(A) - 400) + "m"
            else:
                s = str(int(A))

            return "{0}-{1}.{2}".format(elements[Z], s, self.xs)
        else:
            return None

    @property
    def zaid(self):
        if self.name.endswith('c'):
            return self.name[:self.name.find('.')]
        else:
            return 0

    @property
    def xs(self):
        return self.name[self.name.find('.')+1:]

    def to_xml_node(self, doc):
        node = doc.createElement("ace_table")
        node.setAttribute("name", self.name)
        for attribute in ["alias", "zaid", "type", "metastable", "awr",
                          "temperature", "path", "location"]:
            if hasattr(self, attribute):
                string = str(getattr(self, attribute))

                # Skip metastable and binary if 0
                if attribute == "metastable" and self.metastable == 0:
                    continue

                # Skip any attribute that is none
                if getattr(self, attribute) is None:
                    continue

                # Create attribute node
                node.setAttribute(attribute, string)

        return node

if __name__ == '__main__':
    # Read command line arguments
    if len(sys.argv) < 3:
        sys.exit("Usage: convert_xsdir.py  xsdirFile  xmlFile")
    xsdirFile = sys.argv[1]
    xmlFile = sys.argv[2]

    # Read xsdata and create XML document object
    xsdirObject = Xsdir(xsdirFile)
    doc = xsdirObject.to_xml()

    # Reduce number of lines
    lines = doc.toprettyxml(indent='  ')

    # Write document in pretty XML to specified file
    f = open(xmlFile, 'w')
    f.write(lines)
    f.close()
<commit_msg>Fix bug in convert_xsdir.py.<commit_after>#!/usr/bin/env python2

import os
import sys
from xml.dom.minidom import getDOMImplementation

elements = [None, "H", "He", "Li", "Be", "B", "C", "N", "O", "F", "Ne", "Na",
            "Mg", "Al", "Si", "P", "S", "Cl", "Ar", "K", "Ca", "Sc", "Ti", "V",
            "Cr", "Mn", "Fe", "Co", "Ni", "Cu", "Zn", "Ga", "Ge", "As", "Se",
            "Br", "Kr", "Rb", "Sr", "Y", "Zr", "Nb", "Mo", "Tc", "Ru", "Rh",
            "Pd", "Ag", "Cd", "In", "Sn", "Sb", "Te", "I", "Xe", "Cs", "Ba",
            "La", "Ce", "Pr", "Nd", "Pm", "Sm", "Eu", "Gd", "Tb", "Dy", "Ho",
            "Er", "Tm", "Yb", "Lu", "Hf", "Ta", "W", "Re", "Os", "Ir", "Pt",
            "Au", "Hg", "Tl", "Pb", "Bi", "Po", "At", "Rn", "Fr", "Ra", "Ac",
            "Th", "Pa", "U", "Np", "Pu", "Am", "Cm", "Bk", "Cf", "Es", "Fm",
            "Md", "No", "Lr", "Rf", "Db", "Sg", "Bh", "Hs", "Mt", "Ds", "Rg",
            "Cn"]

class Xsdir(object):

    def __init__(self, filename):
        self.f = open(filename, 'r')
        self.filename = os.path.abspath(filename)
        self.directory = os.path.dirname(filename)
        self.awr = {}
        self.tables = []

        self.filetype = set()
        self.recordlength = set()
        self.entries = set()

        # Read first section (DATAPATH)
        line = self.f.readline()
        words = line.split()
        if words:
            if words[0].lower().startswith('datapath'):
                index = line.index('=')
                self.datapath = line[index+1:].strip()
            else:
                self.f.seek(0)

        # Read second section
        line = self.f.readline()
        words = line.split()
        assert len(words) == 3
        assert words[0].lower() == 'atomic'
        assert words[1].lower() == 'weight'
        assert words[2].lower() == 'ratios'

        while True:
            line = self.f.readline()
            words = line.split()

            # Check for end of second section
            if len(words) % 2 != 0 or words[0] == 'directory':
                break

            for zaid, awr in zip(words[::2], words[1::2]):
                self.awr[zaid] = awr

        # Read third section
        while words[0] != 'directory':
            words = self.f.readline().split()

        while True:
            words = self.f.readline().split()
            if not words:
                break

            # Handle continuation lines
            while words[-1] == '+':
                extraWords = self.f.readline().split()
                words = words[:-1] + extraWords
            assert len(words) >= 7

            # Create XsdirTable object and add to line
            table = XsdirTable(self.directory)
            self.tables.append(table)

            # All tables have at least 7 attributes
            table.name = words[0]
            table.awr = float(words[1])
            table.filename = words[2]
            table.access = words[3]
            table.filetype = int(words[4])
            table.location = int(words[5])
            table.length = int(words[6])

            self.filetype.add(table.filetype)

            if len(words) > 7:
                table.recordlength = int(words[7])
                self.recordlength.add(table.recordlength)
            if len(words) > 8:
                table.entries = int(words[8])
                self.entries.add(table.entries)
            if len(words) > 9:
                table.temperature = float(words[9])
            if len(words) > 10:
                table.ptable = (words[10] == 'ptable')

        if len(self.filetype) == 1:
            if 1 in self.filetype:
                self.filetype = 'ascii'
            elif 2 in self.filetype:
                self.filetype = 'binary'
        else:
            self.filetype = None

        if len(self.recordlength) == 1:
            self.recordlength = list(self.recordlength)[0]
        else:
            self.recordlength = None
        if len(self.entries) == 1:
            self.entries = list(self.entries)[0]
        else:
            self.recordlength = None

    def to_xml(self):
        # Create XML document
        impl = getDOMImplementation()
        doc = impl.createDocument(None, "cross_sections", None)

        # Get root element
        root = doc.documentElement

        # Add a directory node
        if self.directory:
            directoryNode = doc.createElement("directory")
            text = doc.createTextNode(self.directory)
            directoryNode.appendChild(text)
            root.appendChild(directoryNode)

            for table in self.tables:
                table.path = os.path.basename(table.path)

        # Add filetype, record_length and entries nodes
        if self.filetype:
            node = doc.createElement("filetype")
            text = doc.createTextNode(self.filetype)
            node.appendChild(text)
            root.appendChild(node)
        if self.recordlength:
            node = doc.createElement("record_length")
            text = doc.createTextNode(str(self.recordlength))
            node.appendChild(text)
            root.appendChild(node)
        if self.entries:
            node = doc.createElement("entries")
            text = doc.createTextNode(str(self.entries))
            node.appendChild(text)
            root.appendChild(node)

        # Add a node for each table
        for table in self.tables:
            if table.name[-1] in ['e', 'p', 'u', 'h', 'g', 'm', 'd']:
                continue
            node = table.to_xml_node(doc)
            root.appendChild(node)

        return doc

class XsdirTable(object):

    def __init__(self, directory=None):
        self.directory = None
        self.name = None
        self.awr = None
        self.filename = None
        self.access = None
        self.filetype = None
        self.location = None
        self.length = None
        self.recordlength = None
        self.entries = None
        self.temperature = None
        self.ptable = False

    @property
    def path(self):
        if self.directory:
            return os.path.join(self.directory, self.filename)
        else:
            return self.filename

    @path.setter
    def path(self, value):
        self.diretory = ''
        self.filename = value

    @property
    def metastable(self):
        # Only valid for neutron cross-sections
        if not self.name.endswith('c'):
            return

        # Handle special case of Am-242 and Am-242m
        if self.zaid == '95242':
            return 1
        elif self.zaid == '95642':
            return 0

        # All other cases
        A = int(self.zaid) % 1000
        if A > 300:
            return 1
        else:
            return 0

    @property
    def alias(self):
        zaid = self.zaid
        if zaid:
            Z = int(zaid[:-3])
            A = zaid[-3:]

            if A == '000':
                s = 'Nat'
            elif zaid == '95242':
                s = '242m'
            elif zaid == '95642':
                s = '242'
            elif int(A) > 300:
                s = str(int(A) - 400) + "m"
            else:
                s = str(int(A))

            return "{0}-{1}.{2}".format(elements[Z], s, self.xs)
        else:
            return None

    @property
    def zaid(self):
        if self.name.endswith('c'):
            return self.name[:self.name.find('.')]
        else:
            return 0

    @property
    def xs(self):
        return self.name[self.name.find('.')+1:]

    def to_xml_node(self, doc):
        node = doc.createElement("ace_table")
        node.setAttribute("name", self.name)
        for attribute in ["alias", "zaid", "type", "metastable", "awr",
                          "temperature", "path", "location"]:
            if hasattr(self, attribute):
                string = str(getattr(self, attribute))

                # Skip metastable and binary if 0
                if attribute == "metastable" and self.metastable == 0:
                    continue

                # Skip any attribute that is none
                if getattr(self, attribute) is None:
                    continue

                # Create attribute node
                node.setAttribute(attribute, string)

        return node

if __name__ == '__main__':
    # Read command line arguments
    if len(sys.argv) < 3:
        sys.exit("Usage: convert_xsdir.py  xsdirFile  xmlFile")
    xsdirFile = sys.argv[1]
    xmlFile = sys.argv[2]

    # Read xsdata and create XML document object
    xsdirObject = Xsdir(xsdirFile)
    doc = xsdirObject.to_xml()

    # Reduce number of lines
    lines = doc.toprettyxml(indent='  ')

    # Write document in pretty XML to specified file
    f = open(xmlFile, 'w')
    f.write(lines)
    f.close()
<|endoftext|>